Pin CDN Assets with Subresource Integrity
Add SRI hashes to third-party scripts and styles, use crossorigin correctly, and regenerate hashes when the asset version changes so a hijacked CDN cannot inject code.
Task
Protect against a compromised CDN or proxy by verifying third-party asset hashes in the browser.
When to use this
A third-party script from a CDN is loaded without integrity checking, so a modified file on the CDN runs arbitrary code in every user browser.
Prerequisites
- A build step to compute hashes
- Control over the script and link tags
Steps
1. Compute a strong hash (sha384) of each third-party asset at build time.
Expected output: Each asset has a known-good hash.
2. Add the integrity attribute and crossorigin to the tags.
Expected output: The browser verifies bytes before executing.
3. Fail the build if a pinned hash no longer matches the fetched asset.
Expected output: A changed asset cannot silently ship.
4. Regenerate the hash only when intentionally upgrading the dependency.
openssl dgst -sha384 -binary vendor.js | openssl base64 -AExpected output: Integrity is updated deliberately.
Troubleshooting
Problem
Script blocked by SRI
Solution
CORS must allow the asset; without crossorigin the integrity check fails.
Problem
Hash mismatch after a version bump
Solution
Update the pinned hash in the same change as the dependency upgrade.
Limitations
- SRI only applies to scripts and styles with a hash you control; it cannot protect dynamic imports fetched at runtime.
- It fails closed, so a CDN that changes bytes without notice will break the asset until the hash is updated.
Context
Protect against a compromised CDN or proxy by verifying third-party asset hashes in the browser. A third-party script from a CDN is loaded without integrity checking, so a modified file on the CDN runs arbitrary code in every user browser.
Steps
- Compute a strong hash (sha384) of each third-party asset at build time. Expected: Each asset has a known-good hash.
- Add the integrity attribute and crossorigin to the tags. Expected: The browser verifies bytes before executing.
- Fail the build if a pinned hash no longer matches the fetched asset. Expected: A changed asset cannot silently ship.
- Regenerate the hash only when intentionally upgrading the dependency. Expected: Integrity is updated deliberately.
<script src="https://cdn.example.com/lib-4.2.1.min.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous"></script>
Verify
- Each asset has a known-good hash.
- The browser verifies bytes before executing.
- A changed asset cannot silently ship.
- Integrity is updated deliberately.
Limits
- SRI only applies to scripts and styles with a hash you control; it cannot protect dynamic imports fetched at runtime.
- It fails closed, so a CDN that changes bytes without notice will break the asset until the hash is updated.