Subresource Integrity (SRI): the one-line defense against CDN compromise
Here's a nightmare that has actually happened, more than once: a popular script served from a third-party CDN gets quietly swapped for a malicious version, and overnight every site that embeds it starts running the attacker's code in its visitors' browsers — stealing form data, redirecting checkouts, mining whatever. The site owners did nothing wrong except trust a <script src>. Subresource Integrity is the one attribute that would have stopped it cold.
What SRI does
When you load a script or stylesheet from someone else's server, you're trusting that server to send you exactly what you expect — forever. SRI removes that trust. You attach a cryptographic hash of the file you expect to the tag that loads it; the browser downloads the file, recomputes the hash, and if it doesn't match, it refuses to run it. A tampered file simply doesn't execute.
It's the difference between "load whatever is at this URL" and "load this URL only if it's still byte-for-byte what I approved."
How to add it
Two attributes on the tag:
<script src="https://cdn.example.com/lib@1.2.3/lib.min.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous"></script>
integrity— the algorithm-prefixed, base64 hash. Usesha384(the common choice);sha256is the minimum andsha512the strongest.crossorigin="anonymous"— required for cross-origin files. Without it the browser can't read the response body to hash it, and the load fails. People forget this constantly, then wonder why their SRI-protected script won't load at all.
You rarely compute the hash by hand. Most CDNs publish it right next to the file (cdnjs shows the full SRI tag), or generate it yourself:
curl -sL https://cdn.example.com/lib.min.js | openssl dgst -sha384 -binary | openssl base64 -A
Prefix the output with sha384- and you're done.
The limitation that actually matters
SRI is strict by design: the hash must match exactly. That's the strength and the trap. If the file at that URL ever legitimately changes, the hash won't match and the browser will block your own script. So the rule is: only use SRI on a specific, immutable, versioned URL — lib@1.2.3, never lib@latest.
This is exactly why some famous supply-chain attacks did so much damage: the compromised service served different content on every request, so no fixed hash could describe it — meaning SRI couldn't protect it at all. The lesson isn't "SRI failed." It's "never load live, mutable third-party code you can't pin."
A few other limits worth knowing: SRI only covers <script> and <link rel="stylesheet">. It doesn't protect inline scripts, CSS @import, images, iframes, or dynamically imported ES modules. For the things it can't cover, your Content-Security-Policy is the complementary control — CSP governs what is allowed to load; SRI guarantees that what loads is unaltered. Use both.
The maintenance reality
SRI adds one discipline to your workflow: when you bump a library version, you must update its hash in the same change. Forget, and the new file won't match the old hash and your script silently stops loading — a self-inflicted outage that looks baffling until you check the console. Bake hash generation into your build or dependency-update process so it's never a manual afterthought.
And this is the quiet truth about every third-party script on your site: each one is a trust relationship you can't see from the outside until it breaks. The best move is to reduce them — self-host what you can, pin and SRI what you can't, and keep an eye on the security posture around them. Our free site checker grades the defenses that sit alongside SRI — your security headers, TLS and DNS — so the rest of your perimeter is solid while you lock down scripts.
Check the rest of your front-end defenses
SRI locks down third-party scripts; Perimeter grades everything around them — CSP and the other security headers, TLS, and DNS — and re-checks on a schedule so a regression doesn't slip by. Free, no signup.
Monitor your headers → · Agency plan $29/mo, up to 25 domains