Understanding SRI's Scope and Limitations
Subresource Integrity has become an important security control for protecting external JavaScript and stylesheets, but it has definite limitations that developers need to understand. These limitations stem from both the technical nature of hash verification and the constraints of current browser implementations. Understanding what SRI can and cannot protect against helps you implement it effectively and choose appropriate alternative security measures when needed.
Browser Support for SRI
SRI support varies across browsers, though modern browsers have excellent coverage:
Full Support:
- Chrome/Edge: Version 45+ (released August 2015)
- Firefox: Version 43+ (released December 2015)
- Safari: Version 12.1+ (released March 2019)
- Opera: Version 32+ (August 2015)
Partial or Legacy Support:
- Internet Explorer: No support (never implemented)
- Older Safari versions: No support before 12.1
- Older Android browsers: Spotty support, variable across versions
User Agent Statistics: As of 2024, approximately 96%+ of global web traffic comes from browsers with full SRI support. This is excellent coverage, though legacy browser support remains a consideration for some applications.
For applications targeting legacy browsers, you need fallback strategies if SRI verification fails.
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="/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="/lib.js?version=1.0.0" integrity="sha256-..."></script>
If you later update the library:
<script src="/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="lib.js" integrity="sha256-abc+/="></script>
<!-- Incorrect: hexadecimal encoding -->
<script src="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.

