The Hash That Breaks on Saturday: Pinning Vendor Scripts Without Breaking Checkout
Vendor scripts are the guests who never leave. A payments widget, a reviews badge, an analytics tag that someone in marketing swears by — they all arrive with a snippet and a promise. You paste the snippet, it works, and everyone moves on. Then one Saturday morning the vendor ships a patch to the same URL, your Subresource Integrity hash no longer matches, the browser refuses to execute the file, and checkout quietly stops working for anyone unlucky enough to be shopping before lunch.
SRI is worth doing. It's also a lock on a door you don't own, and that changes the operational maths. This is how to pin third-party scripts without turning your site into a hostage situation.
What SRI actually buys you
Subresource Integrity is a browser feature: you add an integrity attribute to a <script> or <link> tag, and the browser checks the fetched file against a cryptographic hash before running it. If the file has changed — because a CDN got compromised, because a transit provider is playing silly beggars, or because the vendor pushed an update — the browser blocks it.
That's the appeal. You're not trusting the vendor's CDN to serve the right bytes; you're trusting maths. For a UK team loading scripts you can't fork or self-host, it's one of the few controls you actually control.
But SRI doesn't tell you why a file changed. It just refuses. And a blocked script often fails silently unless you've wired up error handling. That's the bit most tutorials skip.
The Saturday-morning problem
Vendors update files at stable URLs. That's convenient for them and a nightmare for you. The hash you pinned on Tuesday is wrong by Friday night, and your integrity attribute is now a kill switch you didn't mean to build.
Some vendors publish versioned, immutable URLs — widget-2.4.1.min.js rather than widget.min.js. Use those where you can. Pin the version, not the moving target. If the vendor doesn't offer versioned URLs, ask. If they still don't, you need a loader that expects breakage rather than pretending it won't happen.
The other trap is scope. Every script you pin is another thing that can break. Don't pin all eleven marketing tags because it looks tidy in a security review. Pin the ones that matter, and be honest about what "matters" means: does this script touch money, personal data, or the checkout path? If not, a pin might be more trouble than it's worth.
A loader that verifies, fails over and tells you
The pattern is simple: treat the vendor script as one possible source, keep a known-good fallback, and make failure loud enough that someone can act on it.
const sources = [
{ src: 'https://vendor.example/widget-2.4.1.min.js', integrity: 'sha384-...' },
{ src: '/vendor/widget-2.4.0.min.js', integrity: 'sha384-...' }
];
function loadNext(index) {
if (index >= sources.length) {
reportFailure('vendor-widget', 'all sources failed');
return;
}
const script = document.createElement('script');
script.src = sources[index].src;
script.integrity = sources[index].integrity;
script.crossOrigin = 'anonymous';
script.onerror = () => loadNext(index + 1);
script.onload = () => reportSuccess('vendor-widget', sources[index].src);
document.head.appendChild(script);
}
loadNext(0);
A few rules of the road. Fallbacks only work if you're allowed to self-host a copy — check the vendor's licence, because many prohibit it. If self-hosting isn't allowed, the fallback might be a second vendor URL, a degraded experience, or a clear message to the user rather than a broken button. Don't quietly fail over to an unpinned file; that undoes the point.
Also: alert on the first failure, not the tenth. A beacon to your monitoring stack, an email to the on-call rota, a message in the team channel — whatever you actually read. The goal is to know before a customer does. In the UK, that often means knowing before the Monday morning rush rather than discovering it from a support ticket at 9:15.
Rolling out CSP without a big bang
A Content Security Policy is the natural companion to SRI. It lets you say which scripts are allowed, and it can enforce hash-based rules rather than just hostnames. But don't switch it on in enforce mode on a Friday.
Start with Content-Security-Policy-Report-Only. Collect reports for a couple of weeks. You'll discover scripts you forgot about — the old chat widget, the A/B testing tag, the thing the agency added in 2024 and never documented. Fix the easy stuff first: remove what nobody uses, move what you can to versioned URLs, and decide what genuinely needs an exception.
When you enforce, start with a small policy that covers script sources and leave the rest for later. A partial CSP that holds is better than a comprehensive one you roll back at 6pm. Keep the report endpoint live even after enforcement — reports are how you find out when a vendor sneaks in a new domain.
A short audit checklist
Before you pin anything, ask:
- Does this script touch payments, personal data, or the checkout flow?
- Does the vendor offer versioned, immutable URLs and publish a changelog?
- Is self-hosting permitted by the licence, and do we have a known-good copy?
- Does the CDN send the right CORS headers for SRI to work?
- Is the script needed on every page, or only a few?
- Can it be deferred or loaded after interaction?
- Who gets alerted when it fails, and do they know what to do?
- Have we tested the fallback path, or just assumed it works?
Pinning vendor scripts is a bit like locking a door in a shared building. You don't control the corridor, but you can control your own latch. Do it deliberately, monitor the thing, and don't let a hash mismatch be the first you hear about a vendor update.