---
title: "A CDN script can change under you: lock it with Subresource Integrity"
description: "Add integrity and crossorigin to every script or stylesheet you load from someone else's server, and the browser refuses the file if its content does not match the hash you wrote."
url: https://ihsanalapsi.dev/articles/subresource-integrity-cdn-scripts
lang: en
date: 2026-11-01
updated: 2026-11-01
tags: ["App security", "Web development", "Supply chain security"]
author: Ihsan Alapsi (إحسان العبسي)
---
# A CDN script can change under you: lock it with Subresource Integrity

The most dangerous line on your site may be one you did not write: a `<script>` tag that loads a library from someone else's server. That line runs with every permission your page has, and the server's owner decides what it contains, not you. If your site loads scripts or CSS files from a CDN, below you will find how to lock them to the copy you checked, with one command and two attributes on the tag.

## What is Subresource Integrity?

Subresource Integrity (SRI) is a browser security feature that lets the browser check that a file it fetched from elsewhere arrived unchanged, by comparing it with a hash you wrote in the page.

According to [MDN's Subresource Integrity page](https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity), you add an `integrity` attribute to the tag holding a hash of the file's content, and the file must match it. A hash is a fixed-length fingerprint computed from every byte of the file, and any change to the content gives a different fingerprint.

## Why is the CDN link alone not enough?

Because the link stays the same even when the content behind it changes, and without SRI the browser runs whatever comes back from that address.

The mistake here is simple and human: we trust the address, not the content. We check the library once when we add it, then assume the file at that URL stays the same forever. But if someone reaches the library's account or the CDN's server, they can swap the file, and every site that loads it runs the new code at once, with its page's full permissions. We saw this kind of supply chain attack in the article on [the npm worm that stole AI tool credentials](/articles/npm-testmetest-worm-ai-credentials).

A modified script in your page can read everything typed into your forms, and any cookie not protected by HttpOnly. So check [the locks on your session cookie](/articles/session-cookie-flags-check) too.

## How does the hash stop a modified file?

The browser computes the hash of the file it received and compares it with the value in the `integrity` attribute: if they match it loads the file, and if not it refuses to load it and returns a network error.

So you do not need to know whether the file was tampered with. An attacker can swap the file on the CDN, but cannot change the hash written in your own page, so the browser stops the new file before a single line of it runs. The algorithms the attribute accepts, per MDN, are `sha256`, `sha384` and `sha512`, and [the W3C Subresource Integrity specification](https://www.w3.org/TR/SRI/) requires browsers to support SHA-256, SHA-384 and SHA-512.

## How do you add integrity to a script on your site?

You compute the hash of the copy you use, write it in the `integrity` attribute along with `crossorigin="anonymous"`, then test the page.

1. Pick a link to a fixed version of the library, with the version number in it, not a link that returns the latest version. You end up with a file that only changes when you change the link.
2. Download that file and compute its hash with the command MDN gives (replace `FILENAME.js` with the file's name):

```bash
cat FILENAME.js | openssl dgst -sha384 -binary | openssl base64 -A
```

3. Put the output in the tag after `sha384-`, and add `crossorigin="anonymous"`:

```html
<script
  src="LIBRARY_URL"
  integrity="sha384-THE-OUTPUT-YOU-GOT"
  crossorigin="anonymous"></script>
```

4. Open the page and look at the Console in the developer tools: if the file did not load, either the hash was computed from another copy, or the CDN's server does not send a CORS header.

The same goes for CSS files: both attributes go on the `<link rel="stylesheet">` tag.

## Why does integrity need crossorigin?

Because the browser accepts SRI on a file from another server only when the request uses CORS, and without `crossorigin` the request always fails.

MDN's page explains why: a file loaded from the HTML goes in `no-cors` mode by default, and in that mode SRI could leak to an attacker information about the content of a file they are not allowed to read. So the browser does not allow SRI on a `no-cors` request, and the server holding the file must answer with an `Access-Control-Allow-Origin` header. Most public CDNs send it, but step 4 above is what confirms it for you.

## How do you find the scripts that still lack integrity?

Search your code and page templates for every `<script src>` and every `<link rel="stylesheet">` whose link points to a domain other than yours, and check whether it carries `integrity`.

There is also [a newer header called Integrity-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Integrity-Policy) that makes the browser check that all scripts or stylesheets carry SRI. But MDN marks it "Limited availability", meaning it does not work in some of the most widely used browsers, so treat it as an extra safety net, not a replacement for searching by hand.

And if you pull code from outside in GitHub Actions or in build steps, the same idea applies there: pin the version instead of the name, as we explained in the article on [locking your actions' versions](/articles/github-actions-workflow-lockfiles).

## Where do you start today?

Open your site's home page, count the scripts that come from another domain, and add `integrity` and `crossorigin` to the first of them today.

The lesson for us as developers: a link is an address, not a guarantee. When you lock every outside file to the hash of the copy you checked, any swap of its content stops at the browser before it reaches your users.

If you want someone to check the scripts and libraries your platform loads, along with its other weak spots, [Muhassan audits your platform and hands you a clear fix plan](/muhassan).

## FAQ

**Does a script on my own server need integrity?**

Usually not. The bigger risk is in files from a server you do not control, such as a CDN. A file on your own server is protected by the security of that server.

**What happens if the CDN updates the file at the same URL?**

The browser refuses to load it because the hash no longer matches, and the feature that depends on it stops. That is why you link a fixed version, not the latest one.

**Which hash algorithm should I use?**

sha384 is the common choice in examples, and sha256 and sha512 are accepted too. What matters is that you compute the hash from the exact copy you checked.

**Does integrity replace a Content Security Policy?**

No. integrity checks that one file did not change, and a CSP decides where your site may load scripts from at all. They work together.
