Cybersecurity

What is Subresource Integrity (SRI) and Why Is It Important?

Learn how SRI protects against compromised CDNs and supply chain attacks by verifying resource integrity with cryptographic hashes.

By Inventive HQ Team

Subresource Integrity (SRI) is a browser security feature that lets you attach a cryptographic hash to a <script> or <link> tag so the browser can verify a file was not altered before it runs it. Standardized by the W3C in 2016, SRI works by having the browser compute a SHA-256, SHA-384, or SHA-512 hash of every downloaded resource and compare it against the value in the integrity attribute. If the hashes match, the code executes. If a single byte differs — because a CDN was compromised, a package was hijacked, or a proxy injected something — the browser blocks the resource entirely. It closes the gap between "the file I tested" and "the file my users actually receive."

That is the summary an AI Overview can give you. What it cannot show you is how the check flows byte by byte, why a missing crossorigin attribute silently breaks it, and which real supply-chain attacks it would have stopped. The rest of this guide walks through the mechanism, the exact syntax, the failure modes that trip people up, and a copy-paste workflow — with a diagram and a decision table you can act on.

The problem SRI solves

When you load a library from a CDN — jQuery, a font loader, an analytics snippet, a polyfill service — you are trusting that whoever controls that server sends the same code today that they sent when you tested it. That trust is the attack surface. If the CDN is breached, a maintainer's account is hijacked, or a domain quietly changes hands, the attacker can serve modified JavaScript to every visitor on every site that embeds it. Your own servers stay untouched, your code review passes, and the malicious payload runs with full access to your page — reading form fields, stealing session cookies, skimming credit cards.

This is not hypothetical. The 2018 British Airways breach (Magecart) skimmed 380,000 payment cards through a modified script. The June 2024 polyfill.io incident injected malware into thousands of sites after the domain was sold. In both cases, SRI would have caught the altered bytes and refused to run them.

How the integrity check works

SRI inserts a verification step between "download the file" and "run the file." The browser never trusts the source blindly — it re-derives the hash locally and compares.

How the browser verifies a resource with Subresource Integrity A browser downloads a script from a CDN, computes its hash, and compares it to the integrity attribute. A matching hash runs; a tampered file is blocked. Browser integrity="sha384- Xy9k…" CDN / 3rd party serves script.js (may be tampered) 1. request file 2. return bytes 3. Browser hashes the bytes SHA-384(downloaded file) → compare to integrity value match mismatch Hash matches → run it script executes / styles apply Hash differs → blocked resource dropped, console error

The critical property: the hash is derived from the file's content, not its URL or filename. An attacker can serve their payload from the exact same address, and it still fails, because the bytes are different. There is no way to forge a SHA-384 collision that also does something useful — that is the whole security argument, and it rests on the same cryptographic hash function properties that underpin TLS and digital signatures.

Advertisement

The syntax

A protected script tag has two attributes beyond src:

<script
  src="https://cdn.example.com/library@3.6.0/dist/lib.min.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
  crossorigin="anonymous"
></script>

For a stylesheet, it is identical but on the <link>:

<link
  rel="stylesheet"
  href="https://cdn.example.com/theme@2.1.0/style.css"
  integrity="sha384-9ndCyUa6mg8Z6z9Y9j0nsz3H1r2..."
  crossorigin="anonymous"
/>

The integrity value is <algorithm>-<base64-encoded-digest>. You can supply several, space-separated, and the browser picks the strongest it supports — useful during migrations:

integrity="sha256-abc123... sha384-def456..."

Generating the hash

Never copy a hash from a random website. Generate it yourself from the exact file you intend to pin:

# From a local file
cat lib.min.js | openssl dgst -sha384 -binary | openssl base64 -A

# Straight from the CDN URL
curl -s https://cdn.example.com/library@3.6.0/dist/lib.min.js \
  | openssl dgst -sha384 -binary | openssl base64 -A

Prefix the output with sha384- and drop it into the tag. If you would rather paste a URL and copy a finished tag, the SRI Hash Generator does exactly that. Whatever you use, pin an immutable, versioned URL (library@3.6.0, not library@latest) — a "latest" URL is guaranteed to break your hash the next time upstream ships a release.

SRI vs. the tools people confuse it with

SRI is one layer. It does not replace transport security or origin policy — it complements them. Here is where each fits.

MechanismProtects againstWhat it verifiesWhen to use it
SRIA trusted origin serving altered contentThe exact bytes of a specific file match a known hashEvery third-party <script> and <link> you can pin to a version
TLS / HTTPSTampering in transit between server and browserThe connection is encrypted and the server's certificate is validAlways — but it trusts the server itself completely
Content Security PolicyLoading from unapproved origins; inline-script injectionWhich domains may serve resources at allAlongside SRI, to control where code can come from
CORSUnauthorized cross-origin readsWhether an origin is allowed to read a responseRequired plumbing so SRI can even hash cross-origin files

The short version: TLS trusts the server, CSP trusts the origin list, and SRI trusts nothing but the hash. A CDN with valid HTTPS and an allowed CSP origin can still serve you malware — only SRI catches that. For the full relationship between the two policy layers, see how SRI relates to Content Security Policy.

The failure modes that trip people up

SRI is simple until it silently stops working. Three things break it in the field:

  • Missing or wrong crossorigin. For any cross-origin file you must set crossorigin="anonymous", and the CDN must return an Access-Control-Allow-Origin header. Without CORS the browser cannot read the response body to hash it, so the check fails and the resource is blocked — even though the file is perfectly fine. This is the number-one "SRI mysteriously broke my site" cause.
  • Pinning a mutable URL. If you point at @latest or an un-versioned path, the upstream file changes, the hash no longer matches, and the resource vanishes with only a console error. Always pin an immutable, versioned URL and update the hash deliberately when you upgrade.
  • Regenerating on upgrade. SRI has no auto-update. Bumping a library version without regenerating the hash means the new file fails the old check. Bake hash regeneration into your dependency-update process.

Because a mismatch fails closed — the resource is dropped, not run — a broken hash can take out critical functionality with no visible error to end users. Test in staging after every dependency bump, and watch the browser console for Failed to find a valid digest messages.

What SRI does not cover

SRI is narrow by design. It applies reliably to <script> and <link rel="stylesheet"> (plus preload and modulepreload) — not images, fonts, iframes, or fetch() calls. It only helps for static files with a stable hash; a script that legitimately changes on every request cannot be pinned. And it verifies integrity, not intent: a hash confirms the file is the one you approved, but if you approved a malicious library, SRI faithfully runs it. It defends the delivery path — not your dependency choices. Pair it with dependency auditing and a strong supply-chain security posture.

Bottom line

If your site loads any JavaScript or CSS from a CDN or third party, add SRI to those tags. It costs a hash and a crossorigin attribute, adds no measurable latency, and turns a compromised CDN from a full page takeover into a blocked resource and a console error. The maintenance discipline — pin versions, regenerate on upgrade, keep CORS correct — is the price, and it is far cheaper than a Magecart skimmer running on your checkout page.

Frequently Asked Questions

What is Subresource Integrity (SRI)?

Subresource Integrity is a browser security feature, standardized by the W3C in 2016, that lets you attach a cryptographic hash to a <script> or <link> tag using the integrity attribute. Before the browser runs a script or applies a stylesheet loaded from a CDN or third party, it hashes the downloaded bytes and compares them to the hash you specified. If they do not match exactly, the browser blocks the resource. It guarantees the file you tested is the file that runs, even if the server delivering it is compromised.

How do I generate an SRI hash?

From the command line, pipe the file through OpenSSL: cat script.js | openssl dgst -sha384 -binary | openssl base64 -A. Prefix the result with the algorithm name, so the attribute reads integrity="sha384-<base64digest>". You can also paste a URL or file into the InventiveHQ SRI Hash Generator to get the ready-to-copy tag. Always generate the hash from the exact version of the file you intend to pin.

Which hash algorithms does SRI support?

SRI supports SHA-256, SHA-384, and SHA-512. SHA-384 is the common default. MD5 and SHA-1 are not permitted because they are cryptographically broken. You can list multiple hashes separated by spaces, and the browser uses the strongest algorithm it understands.

Do I need the crossorigin attribute with SRI?

Yes, for any cross-origin resource. SRI on a file loaded from a different origin requires crossorigin="anonymous" and the server must return a valid CORS header (Access-Control-Allow-Origin). Without CORS the browser cannot read the response bytes to hash them, so it treats the check as a failure and blocks the resource. Same-origin resources do not need crossorigin.

What happens if the SRI hash does not match?

The browser refuses to execute the script or apply the stylesheet and reports a network error in the console. The page continues to load, but that specific resource is dropped entirely. There is no partial execution and no fallback unless you code one. This is the intended behavior: a mismatch means the file was altered or corrupted, so failing closed is safer than running unknown code.

Does SRI slow down my site?

The performance cost is negligible. The browser has already downloaded the file, and hashing a few hundred kilobytes with SHA-384 takes microseconds. SRI adds no extra network requests. The real operational cost is maintenance: every time you upgrade a pinned library version, you must regenerate the hash or the resource will silently fail to load.

Does SRI work on images, fonts, or fetch requests?

In practice, no. Browser support for the integrity attribute is reliable only on <script> elements and <link rel="stylesheet"> (plus rel="preload" and rel="modulepreload"). It does not cover images, fonts, iframes, or fetch() requests. For those you rely on TLS, Content Security Policy, and origin controls instead.

How is SRI different from Content Security Policy (CSP)?

They solve different problems and work best together. CSP controls which origins are allowed to load resources at all, while SRI verifies that a specific file from an allowed origin has not been tampered with. CSP says "you may only load scripts from cdn.example.com"; SRI says "and that script must hash to exactly this value." Neither replaces the other.

Would SRI have stopped the polyfill.io supply chain attack?

Yes, for any site that pinned a fixed hash. The June 2024 polyfill.io incident injected malicious code after a domain changed hands, affecting thousands of sites that loaded the script live. Any site using SRI on a pinned version would have seen the modified bytes fail the hash check and the browser would have blocked the malicious payload before it ran.

SRISubresource IntegrityCDN securityweb securitysupply chain