Fix guide · medium · missing_sri_external_script

External script loaded without Subresource Integrity

What this rule means

A <script src="https://..."> tag pulls JavaScript from a third-party host, but has no integrity= attribute. The browser will execute whatever bytes the CDN returns — even if those bytes were swapped by an attacker.

Why it matters

Subresource Integrity (SRI) is the browser-enforced check that the bytes a CDN serves match a hash you ship in your HTML. Without it, every cross-origin <script> tag is a trust delegation: you are saying "I trust whoever runs this CDN, plus whoever can compromise their build pipeline, plus whoever can intercept the connection from the CDN to my user, with full code-execution rights on every page my users load."

That trust has been violated repeatedly:

The fix is cheap (one extra HTML attribute), the failure mode is catastrophic (full XSS-equivalent code execution on every page), and the attacker only has to compromise one CDN to hit thousands of sites at once. SRI is the single highest-leverage hardening step you can take against supply-chain attacks.

How to fix it

Add an integrity= attribute (and crossorigin="anonymous") to every cross-origin <script> and <link rel="stylesheet"> tag.

1. Generate the hash for the asset you're including:

curl -sL https://cdn.example.com/lib.js | openssl dgst -sha384 -binary | openssl base64 -A

2. Add it to the tag:

<script
  src="https://cdn.example.com/lib.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
  crossorigin="anonymous"></script>

3. Pin a specific version. SRI is meaningless if you point at @latest — the hash will mismatch on every release. Use a version that won't move, e.g. /[email protected]/ not /lib/.

Tooling:

Better alternative when feasible: self-host the dependency. npm install it, bundle it with your own JavaScript, and serve it from your origin. SRI becomes unnecessary because there's no third-party trust to extend.

What NOT to do: removing the crossorigin attribute. Without crossorigin="anonymous", the browser can't read the response body to check the integrity hash, and it falls back silently to executing the script. Both attributes are required together.

Did vibecheck flag this on your app?

If you reached this page from a vibecheck inspection report, the redacted match in your scan output is the exact string we found in your bundle. After applying the fix above, run the inspection again — the finding should clear.

Run another inspection