Understanding SRI's Scope and Limitations
Subresource Integrity (SRI) works only on <script> and <link rel="stylesheet"> elements, requires CORS (crossorigin="anonymous") for cross-origin resources, cannot protect inline scripts or dynamically imported modules, and blocks any resource whose bytes change — but it is supported in every modern browser (Chrome/Edge 45+, Firefox 43+, Safari 12.1+), covering roughly 96% of global web traffic. In practice that means SRI is a near-universal control for pinning static third-party files, with a small, well-defined set of things it deliberately does not do.
That's the summary an AI Overview gives you. What it can't give you is the why behind each boundary — why dynamic content breaks the hash, why a failed check has no fallback, why cross-origin needs CORS — or a side-by-side map of every limitation against the workaround. That's the rest of this page.
Browser Support for SRI
SRI has shipped in every modern browser for years, so support is effectively universal outside of retired engines:
| Browser | First version with SRI | Released | Status |
|---|---|---|---|
| Chrome | 45+ | Aug 2015 | Full support |
| Edge | 45+ (Chromium) | 2015 | Full support |
| Firefox | 43+ | Dec 2015 | Full support |
| Safari | 12.1+ | Mar 2019 | Full support |
| Opera | 32+ | 2015 | Full support |
| Internet Explorer | — | — | Never implemented |
| Legacy Android WebView | Varies | — | Spotty / unreliable |
User agent statistics: approximately 96%+ of global web traffic comes from browsers with full SRI support. Because a failed or unsupported check degrades gracefully (older browsers simply ignore the integrity attribute and load the file normally), you can add SRI today without breaking legacy clients — they just don't get the extra protection.
SRI Limitations at a Glance
Before the deep dives, here is every practical limitation mapped to what causes it and what to do instead:
| Limitation | Why it happens | Workaround |
|---|---|---|
Only <script> and <link rel="stylesheet"> are covered | The spec targets those two fetch types only | Use CSP for images, iframes, and other resources |
| No inline scripts | There is no fetched file to hash | Use a CSP nonce or hash for inline code |
No CSS @import or dynamic import() | Those fetches bypass the integrity attribute | Load the file with a real <link>/<script> tag |
| Breaks on dynamic / per-user content | The hash must match fixed bytes exactly | Use CSP nonces/hashes instead of SRI |
| Cross-origin needs CORS | Browsers won't hash an opaque response | Add crossorigin="anonymous" + Access-Control-Allow-Origin |
| No built-in fallback on failure | A blocked resource just doesn't load | Detect failure in JS and load a backup manually |
| Breaks when the CDN updates the file | Hash pins you to exact bytes | Pin immutable versioned URLs; update the hash on upgrade |
| Only SHA-256/384/512, base64-encoded | Weak algorithms are disallowed by spec | Generate hashes with a compliant tool |
Dynamic Content: The Fundamental Limitation
SRI's core limitation is incompatibility with dynamic content. Any resource that changes between requests cannot use SRI:
Dynamic server responses:
// This content changes on each request (per-user configuration)
window.userId = {{ current_user.id }};
window.apiKey = {{ api_key }};
The hash changes with each response, making SRI impossible.
Template-rendered content:
<script src="https://example.com/config?user={{ user_id }}"></script>
Query parameters change the content, invalidating hash-based verification.
Real-time APIs:
<script src="/api/data"></script>
APIs return different content based on application state, time, or other factors.
Server-side template variables:
const version = '{{ app_version }}';
const timestamp = new Date('{{ now }}');
These values change, affecting the hash.
For any of these scenarios, you must use alternatives like CSP with nonces or other security mechanisms.
Query Parameters and URL Caching Issues
When using SRI with query parameters in URLs, you may encounter caching complications:
<script src="https://example.com/lib.js?version=1.0.0" integrity="sha256-..."></script>
If you later update the library:
<script src="https://example.com/lib.js?version=1.0.1" integrity="sha256-..."></script>
Browsers cache based on URL. If /lib.js?version=1.0.0 is cached, the browser might not re-fetch when the URL changes. You need to verify that:
- Query parameters are sufficient to bust cache
- CDN respects Cache-Control headers appropriately
- Version identifiers are unique enough to trigger fresh fetches
Resource Substitution Without SRI
Even with SRI in place, you cannot easily substitute resources. If you need to update a library, you must:
- Update the library file
- Compute the new integrity hash
- Update all HTML references with the new hash
This can be challenging in applications with many HTML files or dynamically generated content.
Solutions include:
- Using build tools to automatically compute and embed hashes
- Versioning resources with unique URLs (lib-v1.js, lib-v2.js) and updating hashes in one central location
- Using Content Security Policy with allowlist instead of SRI for more flexible resource management
Fallback Handling: What Happens When Verification Fails
When SRI verification fails, the browser simply doesn't load the resource. For scripts, this means no error callback or fallback is triggered:
<script src="https://cdn.example.com/library.js"
integrity="sha256-wrong-hash">
</script>
<!-- This code runs regardless of whether the script loaded -->
<script>
// library might not be available here!
library.doSomething(); // ReferenceError if previous script failed to load
</script>
The second script executes even if the first failed, leading to errors. Your application must handle this gracefully:
<script src="https://cdn.example.com/library.js"
integrity="sha256-...">
</script>
<script>
if (typeof library === 'undefined') {
console.error('Required library failed to load');
// Implement fallback behavior
}
</script>
Some frameworks provide better error handling, but you must always assume SRI verification might fail and plan accordingly.
Stylesheet and Font SRI Limitations
SRI works for stylesheets and fonts, but with important limitations:
Stylesheet SRI:
<link rel="stylesheet" href="https://cdn.example.com/style.css" integrity="sha256-...">
If verification fails, the stylesheet isn't loaded, and your page appears unstyled. Users might not understand why the page looks broken and doesn't know to try again.
Font SRI:
<link rel="preload" href="https://fonts.example.com/font.woff2" as="font" integrity="sha256-...">
If the font fails verification, the browser uses a fallback font. This is less critical than script failure but affects appearance.
For stylesheets especially, consider whether the risk of SRI failure (due to CDN issues, network corruption, or attacks) outweighs the security benefit of hash verification.
Performance Implications
Hash Computation Cost - The browser must compute the hash of every SRI-protected resource. This is typically fast (microseconds), but it's not completely free:
- For a single resource, imperceptible
- For many resources (20+), might add a few milliseconds
- On slow devices, might be more noticeable
Network Transmission - Integrity attributes add bytes to your HTML:
<!-- Add 70+ characters per script -->
<script src="..." integrity="sha256-abcdefghijklmnopqrstuvwxyz1234567890abcd="></script>
This is minimal and typically worth the security benefit.
Caching Behavior - If you version resources properly, SRI doesn't negatively impact caching. If you don't, it can be an issue.
Cross-Origin Resource Sharing (CORS) Interactions
SRI doesn't directly interact with CORS, but they operate in the same space:
<script src="https://different-origin.com/lib.js"
crossorigin="anonymous"
integrity="sha256-...">
</script>
For cross-origin scripts with SRI:
- The
crossoriginattribute is required for integrity verification to work - Without it, SRI verification might be skipped
- Ensure the cross-origin server sends appropriate CORS headers
No Fallback Resource Support
One limitation is that SRI doesn't support fallback resources:
<!-- This would be nice but isn't valid -->
<script src="https://cdn.example.com/lib.js"
integrity="sha256-..."
fallback="https://my-server.com/lib-backup.js">
</script>
Instead, you must implement fallback logic manually:
<script src="https://cdn.example.com/lib.js" integrity="sha256-..."></script>
<script>
if (typeof library === 'undefined') {
// Load from backup
var script = document.createElement('script');
script.src = 'https://my-server.com/lib-backup.js';
document.head.appendChild(script);
}
</script>
This adds complexity but ensures your application remains functional even if the primary CDN is compromised or unavailable.
Hexadecimal vs Base64 Hash Encoding
SRI uses base64-encoded hashes, not hexadecimal:
<!-- Correct: base64 encoding -->
<script src="https://example.com/lib.js" integrity="sha256-abc+/="></script>
<!-- Incorrect: hexadecimal encoding -->
<script src="https://example.com/lib.js" integrity="sha256-abc0def"></script>
Hash tools must output base64. Tools that output hexadecimal won't work with SRI. The SRI Hash Generator tool handles this correctly.
Lack of Support for Non-Standard Hash Algorithms
SRI supports specific hash algorithms:
- SHA256 (most common, recommended)
- SHA384 (stronger, supported)
- SHA512 (strongest, supported)
Other algorithms aren't supported:
- MD5 (cryptographically broken, not supported)
- SHA1 (deprecated, not supported)
- BLAKE2 (newer, not yet supported)
Use SHA256 for most cases. Use SHA384 or SHA512 if you need stronger hashing, though SHA256 is considered sufficient for security purposes.
Version Pinning vs Automatic Updates
SRI enforces version pinning—you pin to a specific version by its hash:
<script src="https://cdn.example.com/library-1.2.3.js"
integrity="sha256-abcd1234">
</script>
If the CDN updates the library, the hash changes, and verification fails. This is intentional—it prevents automatic updates that might break your application or introduce vulnerabilities.
This means you must:
- Manually manage library versions
- Update SRI hashes when updating libraries
- Test library updates before deploying
- Accept that you won't automatically get security patches
For some teams, this is a feature; for others, it's a limitation.
Subdomains and SRI
SRI works across subdomains as long as CORS is properly configured:
<script src="https://cdn.subdomain.example.com/lib.js" integrity="sha256-..."></script>
As long as the subdomain serves the resource, SRI verification works. No special configuration is needed.
CSP Interaction and Reporting
SRI violations are reported through CSP when CSP is configured:
<meta http-equiv="Content-Security-Policy" content="report-uri /csp-violations">
SRI failures should be included in CSP violation reports, though browser support for reporting varies.
Recommendations for Managing SRI Limitations
For Dynamic Content - Use CSP with nonces or hashes instead of SRI.
For Update Flexibility - Accept manual update processes or automate them with build tools.
For Fallback Scenarios - Implement manual fallback logic or accept slight styling/functionality degradation.
For Browser Compatibility - 96%+ coverage is excellent, but monitor your specific user agent statistics and implement graceful degradation for legacy browsers.
For Performance - SRI adds minimal overhead; prioritize security over the tiny performance cost.
For Versioning - Use unique URLs (lib-v1.0.0.js) and automate hash computation in your build process.
Conclusion: Understanding SRI's Real-World Constraints
SRI is a powerful security control with excellent modern browser support, but it has real limitations. Dynamic content incompatibility is the most significant, but query parameter handling, fallback scenarios, and version pinning also require careful consideration. Understanding these limitations helps you use SRI effectively where it's appropriate and choose alternative security mechanisms where it isn't. In combination with other security measures like CSP, SRI provides important protection for external static resources while recognizing that no single security control solves all problems.