Cybersecurity

Can You Use SRI with Dynamically Generated Content?

SRI cannot protect content that changes per request. Here's why the hash breaks, what actually protects dynamic scripts, and how to pick between SRI, CSP nonces, and CSP hashes.

By Inventive HQ Team

Subresource Integrity (SRI) cannot protect dynamically generated content — the moment a file's bytes change on any request, the browser recomputes the hash, finds a mismatch, and blocks the resource. SRI works by pinning an external <script> or <link rel="stylesheet"> to a cryptographic hash (sha256, sha384, or sha512) you calculate ahead of time. That model only holds for static, versioned, immutable assets. Personalized output, an embedded timestamp, a per-user token, or a rebuilt minified bundle all shift the bytes, invalidate the hash, and cause the load to fail. For anything that changes per response — and for inline scripts, which have no integrity attribute at all — the correct control is a Content Security Policy nonce (or a CSP hash for fixed inline blocks), not SRI.

That's the summary an AI Overview gives you. Here's what it can't show you: the exact point in the request where the hash comparison fails, a side-by-side of which control to reach for in each situation, and a live generator so you can produce a real SRI hash for the static assets that genuinely qualify. Below is the decision table, an animated diagram of the failure, and the tool.

Which control protects which kind of script?

SRI, CSP nonces, and CSP hashes are not interchangeable. Each fits a different combination of "where does the code live" and "does it change." Pick from the table rather than forcing SRI onto content it was never designed for.

ControlProtectsWorks with dynamic content?Works on inline scripts?Use it when
SRI (integrity)External <script> / <link> filesNo — hash is fixed at build timeNoYou load a static, versioned third-party file (e.g. a pinned CDN library) and want to guarantee its bytes never change
CSP nonce ('nonce-...')Inline and external scripts on that responseYes — fresh nonce per requestYesServer renders markup per request; scripts vary but you control the response
CSP hash ('sha256-...')Inline scripts with fixed contentNo — content must be staticYesYou have a small inline block whose contents are known at build time
CSP script-src allowlistAny script by originYes (origin-level only)PartialYou must permit a whole third-party origin and cannot pin individual files
Self-host + build-time SRIVendored dependenciesNo (that's the point)NoYou want reproducible, tamper-evident dependencies under your own version control

The one-line rule: if the content is fixed and external, use SRI; if it changes per request or is inline, use a CSP nonce. Everything else is a fallback.

Advertisement

Why the hash breaks on dynamic content

The failure is deterministic and worth seeing at the byte level. The browser fetches the resource, computes the digest over the decoded response body, and compares it against your integrity value. Compression (gzip, Brotli) is transparent — it is stripped before hashing — so that never causes a mismatch. What causes a mismatch is any change to the actual payload: a per-user greeting, an injected build timestamp, a re-minified bundle, or server-side content negotiation returning a different file.

How SRI passes on static assets and fails on dynamic ones Two lanes: a static asset whose hash matches and loads, and a dynamic asset whose per-request bytes produce a hash mismatch and get blocked by the browser.

Browser SRI check: same integrity value, two outcomes

Static asset — bytes never change library@1.4.2.js pinned version compute sha384 of decoded body MATCH → run script executes Dynamic asset — bytes change per request app.js?u=alice per-user payload compute sha384 of decoded body MISMATCH browser blocks it

The integrity attribute is identical in both lanes — only the response bytes differ.

Because the check is byte-exact, SRI gives you a strong guarantee (a tampered CDN file will not run) but zero tolerance for variance. That trade is exactly right for a pinned jQuery build and exactly wrong for a script your server assembles per visitor.

Symptom → cause → fix

If you are already fighting SRI failures, the mismatch almost always traces to one of these:

SymptomRoot causeFix
Script blocked with "integrity mismatch" after a CDN updateThe provider re-published the file at the same URL; new bytes, old hashRe-pin to a versioned, immutable URL and regenerate the hash, or self-host
Works same-origin, fails cross-originMissing crossorigin attribute or the server sends no permissive CORS headersAdd crossorigin="anonymous" and ensure the origin returns Access-Control-Allow-Origin
Fails only in productionBuild pipeline re-minifies or fingerprints the file after the hash was computedCompute the hash on the exact deployed artifact, as the last build step
Inline script won't take an integrity value at allSRI has no inline modeSwitch that block to a CSP nonce or a CSP hash
Personalized/timestamped script always blockedContent changes every request — SRI can never matchStop using SRI here; protect it with a per-request CSP nonce

Generate a hash for the assets that actually qualify

For the static, versioned assets that are a fit for SRI, you still need a correct hash. Paste a URL or the file contents below to produce a ready-to-use integrity attribute with your choice of sha256, sha384, or sha512:

Loading interactive tool...

Compute the hash against the exact bytes you will ship — the final, minified, deployed artifact — and pin the tag to an immutable, versioned URL so the provider cannot swap the file underneath you. sha384 is the common default; see our SRI hash algorithm comparison if you need to choose deliberately.

The short version

SRI is a tamper-evidence seal for files that never change. Dynamic content, by definition, changes — so the seal is guaranteed to break. Reach for a CSP nonce when the server renders scripts per request, a CSP hash for fixed inline blocks, and reserve SRI for the pinned third-party libraries where its byte-exact guarantee is a feature rather than a failure. Used together, CSP and SRI cover complementary gaps: CSP decides what is allowed to load and run, and SRI proves a permitted file was not altered.

For the neighboring pieces, see how SRI relates to Content Security Policy, handling CSP for third-party resources, and troubleshooting SRI validation failures.

Frequently Asked Questions

Can SRI protect dynamically generated JavaScript?

No. Subresource Integrity validates a resource against a hash you compute ahead of time. If the file's bytes change on any request — personalized output, an embedded timestamp, a per-user token, or a rebuilt minified bundle — the computed hash no longer matches the integrity attribute and the browser blocks the resource. SRI is built for static, versioned, immutable assets, not content that varies per response.

Does SRI work on inline scripts?

No. The integrity attribute only applies to externally loaded subresources — script src and link rel="stylesheet" (plus preload and modulepreload). There is no integrity attribute for inline scripts. To lock down inline or dynamic scripts you use a Content Security Policy nonce or a CSP hash instead.

What should I use instead of SRI for dynamic scripts?

Use a CSP nonce. On each response the server generates a fresh, unpredictable random value, puts it in the script-src directive as 'nonce-XYZ', and stamps the same value on every trusted script tag. The browser runs only scripts carrying the matching nonce, so the markup can change every request while the protection holds. For inline blocks whose content is fixed at build time, a CSP hash ('sha256-...') also works.

Why does my SRI hash keep failing on a CDN script?

Usually one of three things: the CDN silently updated the file so the bytes changed, the resource is cross-origin and is missing the required crossorigin attribute plus permissive CORS headers, or a build step re-minified the file and shifted whitespace. SRI compares the decoded response body byte-for-byte, so even a one-character difference triggers a block.

Does gzip or Brotli compression break SRI?

No. The browser computes the SRI hash over the decoded response body, after transfer and content encoding are removed. Compression is transparent to the check. What breaks SRI is a change to the actual payload — a different minified build, an injected timestamp, or server-side content negotiation that returns a different file.

Can I combine SRI and CSP on the same page?

Yes, and you should. SRI pins the exact contents of your static third-party assets, while CSP restricts which origins can load scripts at all and protects your inline and dynamic scripts with nonces or hashes. CSP can even require SRI on scripts and styles via the require-sri-for directive in supporting browsers. They cover different gaps.

Is a CSP nonce safe to reuse across requests?

No. A nonce must be unpredictable and generated fresh for every response. If you reuse a nonce or make it guessable, an attacker who can inject markup can simply include the known nonce on their own script tag and bypass the policy entirely. Generate at least 128 bits of randomness per response and never cache the HTML that contains it.

Does SRI stop cross-site scripting (XSS)?

Only a specific slice of it. SRI defends against a trusted third-party file being tampered with — a compromised CDN or supply-chain swap. It does nothing against XSS injected into your own dynamically generated HTML. That injection is what CSP nonces, output encoding, and a web application firewall are for.

SRIdynamic contentCSPweb securityJavaScript security