Loading JavaScript directly from another organisation’s server creates a security dependency that is easy to overlook. Your page may contain only a short <script> tag, but the downloaded file executes with the privileges that your site gives that script. If the file at that URL changes unexpectedly, your users can receive code you never reviewed or deployed.

Subresource Integrity (SRI) gives the browser an expected cryptographic hash for a fetched resource. The browser hashes the bytes it receives and loads the resource only when the result matches the declared value. That turns “load whatever this URL serves” into “load the specific content I approved from this URL.”

This article explains that mental model, how to use SRI for suitable scripts and stylesheets, what happens during updates, and why integrity checking is only one layer of third-party dependency security.

A URL identifies a location, not fixed content

Consider a page that loads a library from a content delivery network (CDN):

<script src="https://cdn.example/library-4.2.0.min.js"></script>

The version-looking path is useful, but the browser does not infer immutability from 4.2.0. It requests the URL and, if the response is usable as a script, executes the bytes it receives.

That creates a trust boundary outside your deployment. The file could change because of a compromised distribution system, an accidental replacement, a publishing mistake, or another failure at the provider. HTTPS protects the connection to the server and helps the browser authenticate that server. It does not promise that the server will return the same file tomorrow that it returned when you reviewed the dependency.

The threat model for SRI is narrower: you know which exact resource bytes you intend to use, but you do not want an unexpected change at the resource location to silently become executable code or an applied stylesheet on your page.

SRI does not determine whether the approved file itself is trustworthy. If you pin a malicious or vulnerable version, a matching hash faithfully approves those same bytes.

Subresource Integrity pins expected content

With SRI, the page supplies both the resource URL and integrity metadata:

<script
  src="https://cdn.example/library-4.2.0.min.js"
  integrity="sha384-BASE64_DIGEST_OF_APPROVED_FILE"
  crossorigin="anonymous"></script>

The digest above is deliberately a placeholder for the shape of the markup, not a value to copy into production. A real deployment must calculate or obtain the digest for the exact file it intends to load.

The browser’s decision can be modelled like this:

fetch resource bytes
        |
        v
hash bytes with declared algorithm
        |
        v
compare with integrity metadata
     /             \
  match           mismatch
    |                 |
load resource      reject resource

The useful property is the comparison. A cryptographic hash acts as a compact fingerprint of the expected bytes. If those bytes change, the digest changes with overwhelming probability for a suitable cryptographic hash function. The browser can therefore reject content that does not match the value supplied by your page.

SRI currently supports integrity metadata using SHA-256, SHA-384, and SHA-512. The security decision does not depend on keeping the digest secret. The digest is normally visible in the page source; its job is to describe the expected content, not to authenticate a user or protect a credential.

The integrity value must come from a trusted decision

SRI is useful only if the page and its integrity metadata are more trustworthy than the resource being checked.

Suppose a build process downloads a third-party library, reviews or otherwise approves that exact artifact, computes its digest, and commits the resulting SRI value with the site’s source. At runtime, a compromised CDN cannot simply replace the library and make the existing page accept it, because the replacement bytes will not match the committed digest.

Now consider a different design: every page request asks the same third-party service for both the script URL and a freshly generated hash. If that service is compromised, it may be able to supply a changed script and the matching changed digest. The comparison still succeeds, but the trust decision has moved back to the compromised party.

This is the central mental model: the integrity hash is an approval record. Generate or obtain it through a path you trust, review changes to it like dependency changes, and deliver it as part of your own trusted page.

Cross-origin SRI also depends on CORS

For a resource loaded from another origin, SRI validation works with Cross-Origin Resource Sharing (CORS). The resource server must return an appropriate Access-Control-Allow-Origin response, and the element should request the resource in CORS mode, commonly with crossorigin="anonymous".

A typical cross-origin script therefore looks like:

<script
  src="https://cdn.example/library-4.2.0.min.js"
  integrity="sha384-..."
  crossorigin="anonymous"></script>

If the CDN does not support the required CORS response, adding an integrity value is not a way to bypass that restriction. Test the real resource and browser behaviour before deploying the change.

The same basic mechanism is available for supported <link> resources such as stylesheets. For example:

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

Do not assume that every kind of fetched browser resource accepts an integrity attribute. Apply SRI where the platform defines it, rather than treating the attribute as a generic checksum mechanism for arbitrary HTML elements.

Pinning changes how dependency updates work

Without SRI, a provider can replace a file behind a stable URL and your page will begin using the replacement automatically. That behaviour may be convenient, but it also means a remote change can alter your application without a corresponding deployment.

With SRI, changing the dependency bytes requires changing the expected digest too. A normal update becomes:

choose new dependency version
          |
          v
obtain exact production artifact
          |
          v
review/test according to your process
          |
          v
compute or verify integrity digest
          |
          v
update URL and/or digest together
          |
          v
deploy

This is intentional friction. The resource no longer updates merely because its host changed the bytes.

It also creates an operational responsibility. If a provider legitimately changes a supposedly stable file while your page retains the old digest, browsers will reject the new response and the dependency can stop working. For that reason, SRI fits especially well with versioned, immutable assets whose bytes are expected to remain fixed.

A URL that intentionally serves frequently changing content is a poor candidate for a fixed digest unless you also have a reliable process for updating the page whenever the content changes. Pinning and automatic mutation are conflicting expectations.

Treat integrity changes like dependency changes

A common mistake is to regenerate SRI hashes automatically whenever a build sees different remote content. That preserves availability but can erase the security decision SRI was meant to enforce.

If an unexpected upstream change causes the build to replace the old digest automatically, the next deployment may approve the changed bytes without anyone asking why they changed.

A stronger workflow makes the change visible. When a dependency update is intended, update the artifact and integrity metadata together, then let normal review and testing examine that diff. If the integrity value changes when no dependency update was expected, investigate before accepting it.

This principle also applies to package managers and vendored assets: a checksum is most valuable when a mismatch stops the process or demands a new approval, rather than silently teaching the system to trust whatever arrived most recently.

Decide what should happen when a pinned resource fails

SRI deliberately fails closed for the resource: when the bytes do not match, the browser refuses to use them. Your application still needs to handle the resulting absence sensibly.

If the rejected script provides an optional analytics feature, losing it may have little effect on the user. If it implements a critical checkout control, the page may become unusable. Replacing the failed resource automatically with an unpinned copy from another URL would restore functionality by removing the integrity guarantee exactly when something unexpected has happened.

For critical dependencies, decide the failure behaviour before deployment. You might self-host the reviewed asset, design the page so a missing enhancement does not corrupt an operation, or provide a separately pinned fallback whose artifact is independently controlled. The right choice depends on the feature and availability requirements.

Monitoring matters too. Browser-side resource failures can otherwise look like random client errors. Your existing client error reporting or synthetic tests should make a pinned dependency failure visible enough for operators to investigate it.

SRI does not make third-party JavaScript low risk

A matching digest answers one question: “Are these the bytes that this page declared acceptable?” It does not answer broader questions about what those bytes can do.

Once an approved third-party script executes in your page, it normally runs in the page’s JavaScript environment. SRI does not sandbox it, restrict its access to the DOM, stop it from making allowed network requests, or repair vulnerabilities in the library. It also cannot protect the page if an attacker can modify your own HTML and replace both the resource and its integrity metadata.

That means the first defensive decision is still whether the third-party script needs to run in your page at all. Removing an unnecessary dependency eliminates its runtime trust relationship. Self-hosting can reduce reliance on a third-party delivery path, although you then own patching and distribution. SRI is most useful when remote hosting is justified and you can pin a specific approved artifact.

Content Security Policy (CSP) can complement SRI by constraining which resources a page may load and, depending on the policy, which scripts may execute. CSP and SRI solve different problems: an origin allowlist can say where a script may come from, while SRI can say which bytes are acceptable at a particular resource load. Neither substitutes for reviewing dependency risk and keeping vulnerable components updated.

Verify the control instead of assuming the markup works

An integrity attribute is easy to add and easy to misconfigure. Test both the success and failure paths.

First, verify that the approved production asset loads with the intended digest and cross-origin configuration. Then, in a controlled test environment, change the expected digest to a non-matching value and confirm that the browser rejects the resource and that the application behaves as designed without it. Browser developer tools should show the failed load, which is also useful when diagnosing production configuration errors.

Keep the digest tied to the exact production bytes. Minification, banner changes, line-ending changes, or any other byte-level modification can produce a different digest even when the code appears functionally equivalent. That sensitivity is the point: SRI verifies content identity, not semantic equivalence.

Make remote code changes explicit

Third-party browser code is part of your application’s execution environment even when it lives outside your repository. If a specific remote script or stylesheet is supposed to stay unchanged, make that expectation enforceable rather than relying on a version-looking URL.

Use Subresource Integrity to bind the resource load to reviewed bytes, keep the integrity metadata under your control, and treat digest changes as dependency changes that deserve review. Then plan for the residual risks: the approved code can still be flawed, your own page must remain trustworthy, and a rejected critical resource can affect availability.

The practical next step is to inventory externally hosted scripts and stylesheets that are expected to be immutable. For each one, decide whether to remove it, self-host it, or pin the exact production artifact with SRI and test what your application does when that check fails.