Cybersecurity

How to Implement SRI on Your Website

A concrete, copy-paste guide to Subresource Integrity: generate sha384 hashes, add integrity + crossorigin to your script and link tags, and stop a compromised CDN from running attacker code in your users' browsers.

By Inventive HQ Team

Subresource Integrity (SRI) is a browser security feature that lets you verify a third-party script or stylesheet has not been tampered with by adding a cryptographic hash to the tag: <script src="https://cdn.example.com/lib.js" integrity="sha384-…" crossorigin="anonymous"></script>. The browser downloads the file, computes its SHA-384 (or SHA-256/SHA-512) hash, and compares it to your integrity value — if they do not match, the file is blocked and never runs. That single attribute is what stands between your users and a compromised CDN silently serving malicious JavaScript on your login page. SRI is defined by the W3C SRI specification and supported by every modern browser.

That is the summary an AI Overview gives you. Here is what it cannot show you: the exact commands to generate the hash, the CORS gotcha that breaks SRI silently, the decision flow for when a hash mismatch is your bug versus a real attack, and a copy-paste checklist you can run against your own <head>. Below is the animated build flow, a live hash generator, and a symptom-to-fix table.

The 60-second version: what SRI actually does

Every time your page loads a third-party file — jQuery from a CDN, a font stylesheet, an analytics widget — you are trusting that server to send exactly the code you expect. If that CDN is breached (a real, recurring attack class known as a supply-chain attack), it can serve modified JavaScript to your visitors, running in your origin, with access to your cookies and forms. The 2018 British Airways Magecart breach and countless skimmer campaigns work exactly this way.

SRI closes that door. You commit a hash of the file's exact bytes into your HTML. The browser will only execute the file if its content still hashes to your committed value. Change one byte — whether an attacker or a legitimate update — and the browser refuses to run it.

How a browser verifies a subresource with SRI A page requests a script from a CDN; the browser hashes the returned bytes and compares to the integrity value, allowing a match and blocking a mismatch. Browser your page CDN lib.js SHA-384 hash the bytes compare to integrity 1. request lib.js 2. bytes returned match to hash - run it mismatch - blocked

Step 1: Generate the integrity hash

SRI hashes are the base64 encoding of a raw SHA digest of the file's bytes — not the hex string you get from most hash tools. The algorithm name is prefixed to the value. There are three valid choices: sha256, sha384, and sha512. Use sha384 as your default.

From the command line (OpenSSL):

cat jquery-3.7.1.min.js | openssl dgst -sha384 -binary | openssl base64 -A

Directly from a URL (curl piped into OpenSSL):

curl -s https://code.jquery.com/jquery-3.7.1.min.js \
  | openssl dgst -sha384 -binary \
  | openssl base64 -A

In the browser, no install: use the live generator below — paste a URL or the file contents and it emits the full integrity attribute for you.

Loading interactive tool...

The -binary flag matters: you must hash the raw digest, then base64 it. If you base64-encode the hex string instead, the value will be wrong and the browser will block your file.

Advertisement

Step 2: Add integrity + crossorigin to the tag

For a script:

<script src="https://code.jquery.com/jquery-3.7.1.min.js"
        integrity="sha384-1H217gwSVyLSIfaLxHbE7dRb3v4mYCKbpQvzx0cegeju1MVsGrX5xXxAvs/HgeFs"
        crossorigin="anonymous"></script>

For a stylesheet:

<link rel="stylesheet"
      href="https://cdn.example.com/bootstrap.min.css"
      integrity="sha384-…"
      crossorigin="anonymous">

The crossorigin="anonymous" attribute is not optional for cross-origin files. SRI needs to read the response bytes to hash them, and the browser only allows that read when the response is CORS-enabled and you request it anonymously (no cookies sent). Omit it on a third-party URL and the browser blocks the file with a CORS error even when the hash is correct.

Step 3: Pin an immutable version — never "latest"

SRI depends on the file's bytes never changing under your committed hash. A URL like https://cdn.example.com/library/latest/lib.js will eventually serve a new release, its hash will no longer match, and your site breaks. Always pin to a versioned, immutable URL:

CDN URL patternSafe with SRI?Why
.../jquery-3.7.1.min.js (explicit version)YesBytes are immutable per version
.../npm/pkg@4.6.2/dist/pkg.js (pinned semver)YesjsDelivr/cdnjs serve fixed content
.../pkg@4/dist/pkg.js (major-range)NoResolves to changing minor versions
.../pkg@latest/pkg.jsNoContent changes on every release
Your own build with content hash in filenameYesFilename changes when content does

Which should you use? For third-party libraries, pin the exact patch version on jsDelivr or cdnjs — both publish the matching SRI hash next to every file. For your own bundled assets, use a build tool (Vite, webpack, esbuild) that emits content-hashed filenames and generates SRI attributes automatically, so the hash and the file are always regenerated together.

Where SRI fails, and what to do about it

Because a mismatch is a hard block, the most common "SRI broke my site" reports are self-inflicted — an updated file with a stale hash. Use this table to triage.

SymptomLikely causeFix
Console: Failed to find a valid digest ... integrity attributeFile content changed (you updated it, or CDN mutated it) but hash was not regeneratedRegenerate the hash from the current file bytes and update the tag
Console: CORS / No 'Access-Control-Allow-Origin' with SRIMissing crossorigin="anonymous" on a cross-origin resourceAdd crossorigin="anonymous" to the tag
Hash never matches even when file looks rightYou base64-encoded the hex digest, or added a trailing newlineUse openssl dgst -sha384 -binary | openssl base64 -A — hash the raw binary digest
Works locally, blocked in productionProd CDN minifies/rewrites the file (e.g. Cloudflare auto-minify)Disable transform features for that path, or hash the transformed output
Font stylesheet (Google Fonts) breaks with SRIThe CSS URL returns different content per browser/UADo not apply SRI to UA-varying endpoints; self-host the font CSS instead
Inline script "won't take" an integrity attributeSRI does not apply to inline codeUse a CSP nonce/hash for inline scripts

Step 4: Enforce site-wide with CSP (optional, defense in depth)

Per-tag integrity attributes protect only the tags you remember to annotate. To require SRI across your whole page, pair it with a Content Security Policy. The require-sri-for script style directive instructs the browser to refuse any script or style that lacks an integrity attribute:

Content-Security-Policy: require-sri-for script style;

Support for require-sri-for is uneven across browsers, so treat it as a hardening bonus rather than your only line — the per-tag attributes remain the reliable mechanism. SRI and CSP are complementary: CSP restricts which origins can load resources; SRI verifies the specific bytes of the files you allow. For the relationship in depth, see how SRI relates to CSP.

Implementation checklist

Run this against your own <head> before you call it done:

  1. Inventory every <script src> and <link rel="stylesheet" href> pointing at a third-party origin.
  2. Pin each to an explicit, immutable version URL — no latest, no floating major ranges.
  3. Generate a sha384 hash for each pinned file (use the generator above or OpenSSL).
  4. Add integrity="sha384-…" to every tag.
  5. Add crossorigin="anonymous" to every cross-origin tag.
  6. Test in the browser with DevTools open — a blocked resource logs an integrity/CORS error in the console.
  7. Document which URLs are pinned so the next dependency bump regenerates the hash instead of breaking silently.
  8. Automate hash regeneration in your build pipeline for first-party assets so hashes can never drift from content.

The bottom line

SRI is one attribute, two values, and a hash — and it converts "we trust our CDN" into "we cryptographically verify our CDN on every page load." It is cheap to add, safe to deploy (unsupported browsers ignore it), and it is the single most direct defense against a compromised third-party script running in your users' browsers. Pin your versions, generate sha384 hashes, add crossorigin="anonymous", and let the browser enforce the rest.

Compare algorithm choices in the SRI hash algorithm comparison, and if you load many third-party resources, read how to handle CSP for third-party resources next.

Frequently Asked Questions

What is Subresource Integrity (SRI)?

SRI is a W3C security feature that lets a browser verify a fetched script or stylesheet against a cryptographic hash you embed in the tag. You add an integrity attribute containing a base64-encoded SHA-256, SHA-384, or SHA-512 digest. If the delivered file's hash does not match, the browser refuses to execute or apply it, blocking tampered CDN files.

How do I generate an SRI hash?

Hash the exact file bytes and base64-encode the digest. On the command line: cat script.js | openssl dgst -sha384 -binary | openssl base64 -A. Prefix the output with the algorithm name, e.g. integrity="sha384-BASE64HERE". Regenerate the hash any time the file content changes, or the browser will block it.

Do I need the crossorigin attribute with SRI?

Yes, for cross-origin resources. SRI requires the response to be CORS-enabled so the browser is allowed to read the bytes it must hash. Add crossorigin="anonymous" to any script or link tag on a third-party origin. Without it the browser cannot verify the resource and blocks it. Same-origin files do not strictly need it.

Which hash algorithm should I use for SRI?

Use SHA-384. All modern browsers support SHA-256, SHA-384, and SHA-512, and SHA-384 is the widely recommended default balancing security and length. MD5 and SHA-1 are not valid SRI algorithms. You can supply multiple hashes separated by spaces, and the browser uses the strongest one it supports.

What happens when an SRI check fails?

The browser treats a hash mismatch as a network error: the script does not execute and the stylesheet does not apply. A console error is logged (a CORS or integrity failure message). This is the intended defense — a mismatch usually means the file was altered, corrupted in transit, or you forgot to update the hash after changing the file.

Can I use SRI with inline scripts?

No. The integrity attribute only works on external resources fetched via src (script) or href (link rel=stylesheet). Inline scripts and styles have no URL to fetch, so SRI does not apply to them. Use a Content Security Policy with nonces or hashes to control inline code instead.

Does SRI work with dynamically loaded or versionless CDN URLs?

SRI only works when the file content is stable. If a CDN URL serves "latest" and silently changes the file, every content change breaks your hash. Always pin to a specific, immutable version URL (for example a versioned jsDelivr or cdnjs path) so the bytes never change under your committed integrity value.

Is SRI a replacement for a Content Security Policy?

No — they solve different problems and work best together. SRI verifies the integrity of specific files you list. CSP controls which origins are allowed to load resources at all. Use CSP's require-sri-for directive (where supported) alongside per-tag integrity attributes for defense in depth.

Which browsers support SRI?

All current major browsers — Chrome, Firefox, Edge, Safari, and Opera — support SRI for scripts and stylesheets. Because unsupported browsers simply ignore the integrity attribute and load the file normally, adding SRI is safe to deploy: it hardens modern browsers with no penalty for old ones.

SRI implementationweb securityCDN protectionintegrity attribute