# Subresource Integrity (/en/docs/web-security/other/subresource-integrity)



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.

<Callout type="warn" title="One directive is dead, one is the modern way">
  The old CSP [`require-sri-for`](/en/docs/web-security/policies/content-security-policy/directives/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](/en/docs/web-security/policies/integrity-policy), which is recent and not yet Baseline. See [Browser support](#browser-support).
</Callout>

## A minimal example [#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.

```html
<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 [#syntax-and-algorithms]

An integrity value is an algorithm prefix, a dash, and a base64-encoded digest of the
response bytes.

```html
<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 `sha256` and a `sha512`
  token, 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 `sha384` tokens, 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 [#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](/tools/sri-hash),
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 [#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.

```http
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 [#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 `Link` header `integrity` parameter, the header-based equivalent of a
  preload.
* Dynamically imported ES modules, through the `integrity` field 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](/platform/supply-chain) 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 [#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](/en/docs/web-security/policies/content-security-policy/values/csp-hashes-nonce)
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 [#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](/en/docs/web-security/policies/integrity-policy)
closes that gap: it tells the browser to block any resource of a given destination
that loads without valid integrity metadata.

```http
Integrity-Policy: blocked-destinations=(script), endpoints=(integrity-endpoint)
```

You wire the named endpoint through a [`Reporting-Endpoints`](/en/docs/web-security/reporting-api/headers/reporting-endpoints)
header:

```http
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](/en/docs/web-security/reporting-api/reports/integrity-violation) 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]

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 [#build-tooling]

Generating and maintaining hashes by hand does not scale, so let the bundler emit
them:

* **Webpack** has the [`webpack-subresource-integrity`](https://www.npmjs.com/package/webpack-subresource-integrity)
  plugin, which writes `integrity` attributes 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`](https://www.npmjs.com/package/@small-tech/vite-plugin-sri).

## Browser support [#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 [#see-also]

* [Integrity-Policy](/en/docs/web-security/policies/integrity-policy)
* [integrity-violation report](/en/docs/web-security/reporting-api/reports/integrity-violation)
* [CSP hashes and nonces](/en/docs/web-security/policies/content-security-policy/values/csp-hashes-nonce)
* [Reporting-Endpoints header](/en/docs/web-security/reporting-api/headers/reporting-endpoints)
* [Subresource Integrity explained](/en/blog/subresource-integrity-sri)
* [How to generate an SRI hash](/en/blog/generate-sri-hash)

## Sources [#sources]

* [W3C, Subresource Integrity](https://www.w3.org/TR/SRI/)
* [MDN, Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity)
* [MDN, Integrity-Policy header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Integrity-Policy)
