for third-party scripts, done right
Every time a page loads a script from an outside CDN, it silently trusts that the code delivered today is the exact code that got tested. If that CDN is compromised, the file's contents can change while the referenced URL stays identical, and the browser happily loads the tampered code anyway. Subresource Integrity addresses exactly this gap: a hash value embedded in the HTML compares the content actually received against the content expected, and blocks execution the moment they diverge.
Table of Contents
- 1. The risk: a compromised CDN changes code without anyone noticing
- 2. How SRI works under the hood
- 3. Generating hash values correctly
- 4. Why crossorigin is a required pairing
- 5. SRI is not just for scripts: securing stylesheets and fonts too
- 6. Limits: SRI does not protect against deliberately malicious but unmodified code
- 7. Ongoing maintenance when the third-party library updates
- 8. Practical recommendation: self-host, or use SRI deliberately
- 9. Conclusion: SRI as a targeted control, not a cure-all
- 10. Summary
- 11. FAQ
1. The risk: a compromised CDN changes code without anyone noticing
Many websites embed external libraries, analytics scripts, or payment widgets not by self-hosting them but by loading them directly from a third-party content delivery network. That saves bandwidth and maintenance work, but carries an implicit trust assumption: the origin server has zero control over what code actually gets served at the referenced URL once the CDN operator itself is compromised, or an attacker gains access to its infrastructure.
Such an attack, often called a supply chain attack, does not even need to target the destination site directly, only a single, widely used third-party service. If an attacker alters the delivered JavaScript, for instance to skim credit card data from forms, every site that embeds that service is affected automatically, with nothing changed in the site's own codebase. This is the exact scenario Subresource Integrity addresses right at the browser level.
<!-- Loading a script with an SRI hash and crossorigin attribute -->
<script
src="https://cdn.example-provider.com/lib/chart.min.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous"
referrerpolicy="no-referrer">
</script>
<!-- If the hash does not match, the browser blocks
execution of the script entirely and logs a
console error instead of running the altered code. -->
2. How SRI works under the hood
The integrity attribute holds a cryptographic hash of the expected file, computed with one of SHA-256, SHA-384, or SHA-512, followed by the base64-encoded digest. Once the browser loads the referenced file, it computes the hash of the content actually received and compares it byte-for-byte against the value stated in the attribute.
If the two values match, the script executes normally. If even a single byte differs, the browser refuses execution entirely and logs the failure to the console, without a single line of the potentially tampered code ever running. This check happens entirely client-side and requires no changes on the serving end, which makes SRI an unusually easy protection to add.
3. Generating hash values correctly
The hash value is generated once from the specific file version actually being embedded, and must be recomputed every time the file's content changes. The most reliable way to do this is from the command line with OpenSSL, downloading the file and hashing it locally instead of blindly trusting the provider's stated value.
Many well-run CDN providers, such as cdnjs or jsDelivr, ship the matching integrity hash directly alongside the embed URL on their site, saving the manual step. It is important to always generate the hash for the exact, versioned file URL, because an unversioned URL like latest.js can change content at any time and would then permanently fail the SRI check.
# Generate an SRI hash locally from a downloaded file
curl -s https://cdn.example-provider.com/lib/chart.min.js -o chart.min.js
openssl dgst -sha384 -binary chart.min.js | openssl base64 -A
# Insert the result into the integrity attribute:
# integrity="sha384-<generated-hash>"
4. Why crossorigin is a required pairing
For the browser to run the integrity check at all, the resource has to be served with correct Cross-Origin Resource Sharing (CORS) headers, which requires the crossorigin attribute on the script tag. Without it, the browser treats the request as a no-CORS request, whose response is considered opaque, making the hash comparison technically impossible, so SRI gets silently skipped, often with no visible error at all.
The value crossorigin="anonymous" is the right choice for most CDN embeds, since it sends the request without credentials such as cookies. In exchange, the provider's server must set the Access-Control-Allow-Origin header correctly, which established CDN providers do by default but which self-hosted internal CDN setups must configure explicitly.
5. SRI is not just for scripts: securing stylesheets and fonts too
Subresource Integrity is not limited to script tags; it works exactly the same way on link tags used to load external stylesheets. A tampered CSS stylesheet might look harmless at first glance, but CSS injection techniques such as exfiltrating form data through attribute selectors or visually overlaying real content with a fake login form make it a genuine security concern.
The integrity attribute paired with crossorigin can be set on the loading link tag for externally hosted web fonts as well. In practice, SRI is especially worth using for stylesheets and fonts served by less established or infrequently updated CDN providers, while large, well-maintained font services carry lower residual risk but can just as easily be protected.
6. Limits: SRI does not protect against deliberately malicious but unmodified code
A common misconception is assuming SRI generally protects against malicious third-party scripts. In reality, SRI only checks whether a file's content matches the content expected at embed time. If the file was already malicious at the moment the hash was generated, for example because a compromised package provider ships malicious code from the start, SRI merely confirms that code as unchanged, without evaluating what it actually does.
SRI also does not protect against attacks that bypass the file content entirely, such as DNS hijacking pointing to a completely different, attacker-controlled domain with its own matching hash, or scripts that dynamically load additional code at runtime outside the SRI-protected boundary. Comprehensive protection therefore always pairs SRI with a restrictive Content Security Policy that further limits which domains scripts may load from in the first place.
7. Ongoing maintenance when the third-party library updates
The practical downside of SRI is ongoing maintenance overhead: any content change to the embedded file, even a seemingly minor patch update, changes the hash value and immediately blocks execution the moment the old integrity attribute is not updated to match. Teams using SRI therefore need a process that automatically regenerates the matching hash and rolls it out together with every intentional version bump.
In modern build pipelines, bundlers like Webpack or Vite handle this automatically for self-hosted assets, keeping the hash in sync with the actual file on every build. For externally loaded CDN resources, the responsibility stays with the team, which is why a small CI script that regularly checks whether embedded hash values still match the currently served files is well worth the effort.
8. Practical recommendation: self-host, or use SRI deliberately
For scripts that rarely change content and touch security-critical functions like payment processing or authentication, SRI is a sensible, comparatively easy protection to add. For frequently updated libraries with a high release cadence, it is often worth weighing whether to self-host the file instead and manage it through the team's own build pipeline, where integrity is already guaranteed by version control.
As a rule of thumb: the more critical the function of the embedded script and the less often its content changes, the more clearly SRI pays off. For volatile, daily-updated analytics or advertising scripts, on the other hand, the maintenance burden often outweighs the security benefit, which is why a strict CSP with a tightly scoped domain list is usually the more practical alternative there.
9. Conclusion: SRI as a targeted control, not a cure-all
Subresource Integrity solves a very specific but genuinely relevant problem: the undetected, after-the-fact tampering of an already embedded third-party script. With a single HTML attribute, paired with correct CORS setup, this risk can be effectively closed for security-critical, rarely updated scripts without much overhead.
What matters is keeping a realistic understanding of its limits: SRI verifies immutability, not the trustworthiness of the original content. A thorough security approach to third-party scripts therefore always pairs SRI with a restrictive Content Security Policy and a deliberate, kept-small selection of trusted third-party providers.
| Aspect | With SRI | Without SRI | Recommendation |
|---|---|---|---|
| Compromised CDN | Execution gets blocked | Tampered code runs unnoticed | Enable SRI for critical scripts |
| Already malicious origin code | Confirmed, not detected | Also not detected | Choose providers carefully |
| Frequent version updates | Higher maintenance overhead | No extra overhead | Consider self-hosting instead of SRI |
| Browser support | All modern browsers | Not relevant | No compatibility concern |
| Pairing with CSP | Covers additional attack vectors | No protection against DNS hijacking | Always use together |
Mironsoft
Security audits, OWASP-compliant hardening, and secure architecture
Applications that actually hold up against a real attack attempt?
We review existing applications for classic OWASP vulnerabilities, insecure authentication, and missing input validation, then build an architecture that structurally reduces attack surface instead of just patching individual symptoms.
Security Audit
Systematically checking OWASP Top 10, auth flows, and input validation for vulnerabilities.
Secure Architecture
Building rate limiting, encryption, and access controls correctly from the ground up.
Incident Readiness
Establishing logging, monitoring, and response processes for when things go wrong.
10. Summary
Subresource Integrity for third-party scripts at a glance
Mechanism
Browser-side hash comparison blocks scripts whose content diverges.
Requirement
A correct crossorigin attribute and matching CORS headers are mandatory.
Limit
SRI confirms immutability, not the trustworthiness of the original code.
Complement
A restrictive Content Security Policy closes additional attack vectors.