← All articles · May 1, 2026 · CheckoutProof

A Merchant's Guide to Subresource Integrity (SRI): How to Lock Down Third-Party Scripts

Subresource Integrity (SRI) is the simplest, cheapest, most-effective single control you can add to a payment page to satisfy PCI 6.4.3’s “proof of integrity” requirement. It is also widely misunderstood. This article explains what it does, how to add it correctly, and where the limits are.

What SRI actually is

When the browser loads a script from another domain, you have to trust that domain to serve the right code. If that domain gets compromised, your customers get whatever the attacker decided to put there.

SRI fixes that with a cryptographic seal. You compute a hash of the script’s content, attach that hash to the <script> tag, and the browser refuses to execute the script if its content doesn’t match.

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

If widget-1.4.2.min.js was tampered with — by an attacker compromising the CDN, by a vendor pushing an unauthorized update, by a malicious browser extension — the hash changes and the browser refuses to run it. You don’t need to trust anyone; the math protects you.

This is supported in every modern browser (Chrome, Firefox, Safari, Edge). It’s free. It’s fast. It’s been the recommended baseline for client-side security since 2016.

The reason most merchants don’t have it on their checkout pages is that nobody told them. Now you know.

How to compute the hash

The hash algorithm in the integrity attribute can be sha256, sha384, or sha512. PCI auditors expect sha384 or sha512. Use sha384.

The hash is base64-encoded.

From the command line, with curl and openssl:

curl -s https://cdn.example.com/widget-1.4.2.min.js \
  | openssl dgst -sha384 -binary \
  | openssl base64 -A

That outputs something like oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC.

Prefix it with sha384- and that’s the value of your integrity attribute:

integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"

If you’d rather click through a UI: srihash.org is a long-standing free tool that does this in the browser. Don’t paste internal scripts into it; only use it for public CDN URLs.

What the crossorigin="anonymous" part does

Browsers refuse to enforce SRI on cross-origin scripts unless the response includes the right CORS headers. crossorigin="anonymous" tells the browser to make a CORS request without sending cookies or auth headers, and to enforce SRI on the response.

You almost always want crossorigin="anonymous" when adding integrity. The exception: if the script is on your own domain (/wp-content/themes/foo/script.js for a WordPress site), you can omit crossorigin because there’s no cross-origin question.

If you add integrity without crossorigin to a third-party script and that third party doesn’t send Access-Control-Allow-Origin, the browser will refuse to execute the script even if the hash matches. Add the attribute.

When SRI works perfectly

SRI is straightforward when:

This describes most CDN-hosted libraries: jQuery from a CDN, popular open-source bundles, payment-processor SDKs that publish versioned URLs (Stripe.js does this).

For these, add SRI today. It’s a one-line change per script and it eliminates an entire class of supply-chain attacks.

When SRI doesn’t work

Four scenarios where pinning a hash is the wrong answer:

1. The vendor only publishes a “latest” URL

Some vendors host their script at one URL and push updates whenever they want. Google Tag Manager does this. Cloudflare’s bot protection does this. Most A/B testing tools do this.

If you pin a hash, the next vendor update breaks your page (the hash mismatches and the browser refuses to run). If you don’t pin a hash, you have no integrity proof.

The honest answer: either ask the vendor to publish versioned URLs, or accept that this script is not protected by SRI and lean on CSP and monitoring instead. Some merchants ask vendors and get versioned URLs as a result; this is worth doing for any vendor whose script lives on your payment page.

2. The script is generated server-side per request

Some scripts include personalization (the user’s session ID, an A/B test bucket, an experimentation token). The content varies per request, so no single hash is correct.

For these, SRI is impossible. You can only fall back to:

3. Inline scripts

<script>console.log('hi')</script> has no integrity attribute. SRI is for external scripts only.

You control inline scripts directly — they’re in your own HTML — so the integrity question is “did our HTML get modified?” rather than “did a third party’s CDN get compromised?”. The answer is the same as the rest of your site: code review, server-side intrusion detection, and a CSP that blocks unauthorized inline scripts.

If you can move inline content into static external files with versioned URLs, do — it lets you use SRI on what was previously inline.

4. Dynamically injected scripts

A common pattern: your site loads tag-manager.js, and tag-manager.js then dynamically creates new <script> elements pointing at other vendors. The dynamically-injected scripts don’t go through your HTML at all, so you have no place to put an integrity attribute.

Newer browsers support Trusted Types and a CSP require-sri-for directive that can force SRI on dynamic injection. They’re not yet universally deployed. The pragmatic answer for now is: every domain your tag manager can inject from must be in your CSP script-src allowlist, and you monitor for new domains showing up.

How auditors evaluate SRI coverage

When a QSA reviews your 6.4.3 implementation, they look at the script inventory and ask, for each entry:

A 100% SRI-coverage checkout is rare in the real world. A well-documented mix of SRI plus CSP plus monitoring is the realistic target.

The thing auditors mark down is unjustified gaps — a script with no SRI and no documented reason. That’s the case where you don’t know what you’re trusting.

Practical: rolling out SRI on a real checkout page

If you’re starting from zero on a 25-script checkout, do it in this order:

  1. Run a free scan to get the script inventory. The report will tell you which scripts already have SRI and which don’t.
  2. Group the no-SRI scripts by category:
    • “External, versioned URL, vendor I trust” → highest priority. Compute hashes, add integrity and crossorigin="anonymous". Done.
    • “External, latest-URL only” → file a ticket with the vendor asking for versioned URLs. While waiting, add to your CSP script-src.
    • “Inline scripts I author” → consider moving to versioned external files.
    • “Inline scripts a plugin or theme writes” → talk to the plugin author or pin the plugin version.
  3. Test in a non-production environment first. Adding integrity to a script that turns out to be the wrong hash will silently break that script. Roll out one at a time, test in a staging/preview environment, watch for errors.
  4. Set up monitoring. Once SRI is in place, you want to know immediately if a script’s hash mismatch starts firing — that’s either an attack or a vendor pushing an unauthorized update, and you want to investigate.

SRI is part of a kit, not a complete answer

PCI 6.4.3 doesn’t say “use SRI.” It says “have a method to detect tampering.” SRI is the cleanest method when it works, but it’s one tool. Combine with:

Do all three, and the next Magecart variant has nowhere to land. Do one and skip the others, and you’ve left a gap an attacker can use.

Run a free scan of your checkout to see how many scripts you’d need to SRI today.


Run a free PCI 6.4.3 scan of your checkout page. Get the script inventory and a one-page PDF report. Try it now →