Subresource Integrity (SRI): How to Hash Your Assets and Stop Supply-Chain Surprises

By · Updated

Third-party scripts are a trust fall. SRI lets you pin exact bytes with a hash so a swapped or tampered file won’t execute. Here’s how I generate hashes, wire them into tags and CSP, and automate the whole thing so it never goes stale.

Disclaimer: The information in this article is provided for educational and informational purposes only and does not constitute legal, financial, or professional advice. All content is offered “as-is” without warranties of any kind. Readers are solely responsible for how they choose to use this information and must ensure that any actions comply with all applicable local, national, and international laws and regulations. We expressly disclaim liability for any losses, damages, or consequences that may arise from misuse or misinterpretation of this material. Always apply the information only within authorized, ethical, and legal contexts.

For more details, see our Terms of Service.

What Subresource Integrity Actually Does

Subresource Integrity (SRI) tells the browser “only run this script or stylesheet if its bytes match this hash.” If a CDN gets compromised or a version changes unexpectedly, the browser refuses to load it. No match, no execute.

SRI is a tamper-evident seal for <script> and <link rel="stylesheet">.

Specs & guidance: W3C SRI, MDN: SRI.

Generate Correct Hashes (SHA-256/384/512)

Use a stable tool and base64-encode the digest. I default to SHA-384 for a good security/size trade-off.

macOS / Linux (OpenSSL)

# Hash a local file
openssl dgst -sha384 -binary ./assets/js/app.min.js | openssl base64 -A
# Output example:
# 0C9o3qg6m3f4yM...TruncatedForSpace...

Node (cross-platform)

node -e "const fs=require('fs'),c=fs.readFileSync('assets/js/app.min.js');\
const h=require('crypto').createHash('sha384').update(c).digest('base64');\
console.log(h)"

The integrity value becomes sha384-BASE64_HASH.

Wire SRI Into Your HTML (Correctly)

Add integrity and crossorigin="anonymous" to your tags. If bytes change, the resource won’t load.

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

<script defer
  src="https://cdn.example.com/js/app.min.js"
  integrity="sha384-BASE64_HASH"
  crossorigin="anonymous"></script>

If you self-host, you can still use SRI for defense-in-depth. Use with CSP & modern headers for a layered model.

Pair SRI With a Tight Content-Security-Policy

SRI covers tampering. CSP covers where resources may load from and whether inline code runs. Together, they shut down a lot of supply-chain/XSS shenanigans.

Content-Security-Policy:
  default-src 'self';
  script-src 'self' https://cdn.example.com;
  style-src  'self' https://cdn.example.com;
  object-src 'none';
  base-uri   'self';
  frame-ancestors 'none';
  upgrade-insecure-requests;

Learn more: MDN: CSP, Google CSP Guide.

Automate Hashing in Your Build Pipeline

Humans forget; builds don’t. Hash artifacts during CI and inject the integrity attribute at template render. Here’s a lightweight Node snippet you can adapt for Eleventy/Nunjucks or any static build.

// build/sri.js
const { createHash } = require('crypto');
const { readFileSync, writeFileSync } = require('fs');
const files = [
  { path: 'dist/js/app.min.js',   key: 'app_js' },
  { path: 'dist/css/site.min.css', key: 'site_css' },
];
const sri = {};
for (const f of files) {
  const buf = readFileSync(f.path);
  const b64 = createHash('sha384').update(buf).digest('base64');
  sri[f.key] = `sha384-${b64}`;
}
writeFileSync('.cache/sri.json', JSON.stringify(sri, null, 2));

Consume .cache/sri.json inside your Nunjucks templates to populate integrity.

Common SRI Gotchas (and Fixes)

  • Hash mismatch after deploy: The CDN re-minified your file. Fix by hashing the final bytes you serve.
  • Inline scripts + CSP: Prefer external files. If you must inline, use 'nonce-xyz' and rotate per request.
  • Cross-origin without crossorigin: Add crossorigin="anonymous" so the browser can verify.
  • Version pinning: If the CDN version changes, your SRI breaks (by design). Pin versions or automate updates.

Authoritative References

Where to Go Next

Lock down the browser surface area with HTTP Security Headers, and don’t miss the bigger picture in Nothing Deletes—policies matter as much as code.

Spot an error or a better angle? Tell me and I’ll update the piece. I’ll credit you by name—or keep it anonymous if you prefer. Accuracy > ego.

Portrait of Mason Goulding

Mason Goulding · Founder, Maelstrom Web Services

Builder of fast, hand-coded static sites with SEO baked in. Stack: Eleventy · Vanilla JS · Netlify · Figma

With 10 years of writing expertise and currently pursuing advanced studies in computer science and mathematics, Mason blends human behavior insights with technical execution. His Master’s research at CSU–Sacramento examined how COVID-19 shaped social interactions in academic spaces — see his thesis on Relational Interactions in Digital Spaces During the COVID-19 Pandemic . He applies his unique background and skills to create successful builds for California SMBs.

Every build follows Google’s E-E-A-T standards: scalable, accessible, and future-proof.