The fix, in one snippet
<script src="https://cdn.example.com/lib.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous"></script>
Illustrative values. Change the paths, hostnames and options to match your own site before using it.
The sections below explain what is tested, why it matters and the alternatives.
What we test
Scan.now parses the homepage for <script src> and <link rel="stylesheet" href> elements whose host is outside the page's registrable domain. For each one it checks for an integrity attribute, validates its format (sha256-, sha384- or sha512- followed by base64), and checks for crossorigin="anonymous", without which browsers cannot verify a cross-origin file and refuse to load it. Elements lacking integrity fail the check at low severity. Scan.now does not fetch the files to recompute hashes. It also recognises scripts that are designed to change without notice, such as Google Tag Manager, gtag.js and most analytics loaders, and notes that SRI cannot be applied to them; for those, a strict Content-Security-Policy and vendor trust are the controls. A full list of third-party hosts is in external-scripts-inventory.
Why it matters
Loading a script from a CDN means trusting the CDN operator, its DNS, its TLS certificate and every future owner of the domain, permanently. In June 2024 the domain polyfill.io, whose script was embedded on more than a hundred thousand sites, was sold and began serving code that redirected visitors to scam pages, as reported by Sansec. In 2018 the British Airways payment page was skimmed through a modified copy of a script the site loaded from a third party. Subresource Integrity binds the tag to a specific hash: if the delivered bytes differ, the browser refuses to execute them and the page degrades rather than the attacker succeeding. It costs nothing at runtime and is supported by every current browser. The SRI guide covers generating hashes and the limits of the technique.
How to fix it
Compute the hash of the exact file you reference and add it to the tag:
curl -s https://cdn.example.com/lib/1.2.3/lib.min.js | openssl dgst -sha384 -binary | openssl base64 -A
<script src="https://cdn.example.com/lib/1.2.3/lib.min.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous"></script>
Pin the URL to a version, never to latest, or the hash will stop matching at the next release. Most CDNs (cdnjs, jsDelivr) display the SRI hash next to each file. In a build pipeline, webpack's webpack-subresource-integrity plugin and Vite's equivalents emit hashes automatically:
// webpack.config.js
const { SubresourceIntegrityPlugin } = require('webpack-subresource-integrity');
module.exports = {
output: { crossOriginLoading: 'anonymous' },
plugins: [new SubresourceIntegrityPlugin()],
};
Where a vendor script cannot be pinned, self-host a vetted copy and update it deliberately, or isolate the vendor in an iframe. Combine SRI with a CSP script-src that lists only the hosts you expect, so an unpinned tag cannot simply be added elsewhere.
Where this fits
Third-party scripts without Subresource Integrity is check 7 of 10 that the website vulnerability scanner runs under page content and javascript, ordered the way they are worth fixing. That ordering is the point: Fixing this one while the check above it still fails buys less than it looks like.
Fix this one first
Above it in the same category sits Sensitive information in HTML comments (low), where hTML comments in the page source contain material that looks internal: Credentials, TODO notes, internal hostnames or IP addresses, file paths, or links to unpublished areas of the site. An attacker who has that does not need this, so it is the better use of the same hour.
What fixing this still leaves open
Third-party scripts without Subresource Integrity closes one route in. Immediately below it: Inline event handlers and scripts, where the page relies on inline scripts, on* event-handler attributes or javascript: URLs; Password field autocomplete, where password fields on the page either try to disable autocomplete, which browsers ignore and password managers dislike, or lack the autocomplete tokens that let password managers fill and generate credentials safely; Third-party script inventory, where an inventory of every script the page loads from other domains.
Found in the same scan
The website vulnerability scanner reports this alongside checks from other categories that are at least as serious, including Certificate chain and hostname validation, where the certificate presented for this hostname did not validate: The chain does not reach a trusted root, an intermediate is missing, the name does not match, or the certificate is self-signed or expired, and Exposed .env configuration file, where a .env configuration file is served from the web root. A single run of website vulnerability scanner answers all of them at once.
The first few lines
You are a senior web engineer. I ran a security and SEO scanner against my site and it reported the finding below. Fix it properly rather than suppressing the symptom.
Finding: Third-party scripts without Subresource Integrity (low severity)
Scanner check id: subresource-integrity
The rest of this prompt names the pages and line numbers we found the problem on, the configuration to change, and the constraints a good answer has to respect. It is free, it just needs an account so the work is not scraped wholesale.
Sign in with GoogleSigning in is free and takes one click. We store your email address and nothing else.