Subresource Integrity
SRI is the integrity attribute that makes the browser hash a fetched script or stylesheet and refuse it on mismatch, defending against a tampered CDN.
Last update:
Subresource Integrity (SRI) is the integrity attribute you add to a <script> or
<link rel="stylesheet"> that loads code from another host. The browser hashes the
bytes it fetches and compares them to the hash you wrote. If they do not match, the
browser refuses to run or apply the resource and treats it as a network error. It
defends against one specific threat: a third-party host or content delivery network
(CDN) that serves you tampered or compromised code.
One directive is dead, one is the modern way
The old CSP require-sri-for directive never shipped to a stable browser and is abandoned. Do not use it. To require SRI today you use the Integrity-Policy header, which is recent and not yet Baseline. See Browser support.
A minimal example
You add the hash, the resource's host, and (for a cross-origin host) the
crossorigin attribute. The browser does the rest.
<script
src="https://cdn.example.com/library.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous"
></script>If the file at that URL changes by even one byte, the hash no longer matches and the browser drops the script. That is the point: you pin an exact, known-good version.
Syntax and algorithms
An integrity value is an algorithm prefix, a dash, and a base64-encoded digest of the response bytes.
<link
rel="stylesheet"
href="https://cdn.example.com/app.css"
integrity="sha384-VuArbKap7CY5uykM6oqf+R9GqQ8Kux9rx7HNQlGYl1kPzQho1wx4JwY8wCdgcRRap"
crossorigin="anonymous"
/>Three hash functions are allowed: sha256, sha384, and sha512. You can list
several space-separated tokens, and how the browser treats them depends on whether
the algorithms differ:
- Different algorithms (strongest wins). If you list a
sha256and asha512token, the browser picks the strongest algorithm present and validates against only that one. Listing a weaker hash next to a stronger one does not weaken the check. - Same algorithm (any match). If you list two
sha384tokens, the resource is accepted when it matches either one. This is how you allow more than one acceptable payload, for example during a rollover between two file versions.
The digest is the hash of the raw response body, base64-encoded, not a hash of the URL or the file name.
How to generate the hash
The integrity value is the base64-encoded digest of the raw response bytes, prefixed
with the algorithm (sha384-). Generate it with our SRI generator,
which produces the full integrity value from a URL or a file and returns the
sha256, sha384, and sha512 variants to paste into the attribute.
The crossorigin requirement
SRI relies on Cross-Origin Resource Sharing (CORS). The browser cannot read the bytes of an opaque cross-origin response, so it cannot verify a hash against them.
For a cross-origin resource, the integrity attribute does nothing on its own.
You must also set crossorigin="anonymous" (or use-credentials), and the serving
host must return an Access-Control-Allow-Origin header that permits your origin.
Miss either piece and the resource always fails to load.
Access-Control-Allow-Origin: *For a same-origin resource the browser can already read the bytes, so no
crossorigin attribute is needed.
What SRI covers and what it does not
SRI applies to a fixed set of resource types:
<script>elements.<link rel="stylesheet">.<link rel="preload">and<link rel="modulepreload">.- The HTTP
Linkheaderintegrityparameter, the header-based equivalent of a preload. - Dynamically imported ES modules, through the
integrityfield of an import map, supported across current Chrome, Firefox, and Safari.
It does not cover images, audio, video, <iframe>, or <object> today.
The cost is maintenance. SRI needs a pinned, immutable file. A resource that mutates, a CDN that auto-minifies, or a URL that always points at the "latest" build, breaks the hash on every change. You have to regenerate the hash whenever the file legitimately changes, which is why teams pin a versioned URL and update both the URL and the hash together. CentralCSP's script inventory detects the third-party scripts on your pages and flags when one of them changes, which is the signal that an SRI hash needs updating or that something shifted unexpectedly.
SRI hashes vs CSP hash sources
These look identical and mean different things, so it is worth keeping them apart.
| SRI hash | CSP hash source | |
|---|---|---|
| Lives on | The integrity attribute of an element | A script-src / style-src source in the policy |
| Hashes | The bytes of an external resource fetched by URL | The text content of an inline element |
| Prefix | sha256- / sha384- / sha512- | sha256- / sha384- / sha512- |
Both use the same sha256-, sha384-, and sha512- base64 prefix, but the input
differs: SRI hashes the response body of a resource loaded from a URL, while a CSP
hash source
hashes the inline content of an element so the policy can allow it. The same string in
the wrong place will not do what you expect.
Requiring SRI with Integrity-Policy
SRI is opt-in per element. Nothing stops a developer from adding a new external script
without an integrity attribute. The Integrity-Policy header
closes that gap: it tells the browser to block any resource of a given destination
that loads without valid integrity metadata.
Integrity-Policy: blocked-destinations=(script), endpoints=(integrity-endpoint)You wire the named endpoint through a Reporting-Endpoints
header:
Reporting-Endpoints: integrity-endpoint="https://<Endpoint-ID>.report.centralcsp.com"A script without valid integrity is then blocked, and the browser emits an
integrity-violation report to
that endpoint. A report-only variant, Integrity-Policy-Report-Only, reports the
same violations without blocking, so you can measure coverage before enforcing.
SRI and CSP
SRI and CSP are orthogonal controls that you run together. CSP decides whether a script is allowed to run at all and how trust propagates between scripts. SRI verifies that the bytes of an allowed script are the exact ones you expected. A script can pass CSP and still be tampered with; SRI is what catches that.
The old way to combine them was the CSP require-sri-for directive, which would have
forced integrity metadata on scripts or styles. It never shipped to a stable browser
and is abandoned, so do not reach for it. Its role is now filled by the
Integrity-Policy header above.
Build tooling
Generating and maintaining hashes by hand does not scale, so let the bundler emit them:
- Webpack has the
webpack-subresource-integrityplugin, which writesintegrityattributes automatically and handles code-split dynamic imports. - Vite ships no first-party SRI, so use a community plugin such as
@small-tech/vite-plugin-sri.
Browser support
The core integrity attribute on scripts and stylesheets is widely supported across
modern browsers. The require-sri-for CSP directive never shipped and is dead. The
Integrity-Policy header is recent: script-destination enforcement ships in Chrome,
Firefox, and Safari, but it is not yet Baseline.
See also
- Integrity-Policy
- integrity-violation report
- CSP hashes and nonces
- Reporting-Endpoints header
- Subresource Integrity explained
- How to generate an SRI hash