Every third-party script on your checkout, login or admin page runs with the same privileges as the user who loaded it. If the host serving that script is compromised, the attacker gets those privileges too, much as with XSS. The fix starts with knowing which scripts load, then removing what you can and pinning or restricting the rest.
Know what runs on the sensitive pages
The OWASP cheat sheet on third-party JavaScript names three risks: loss of control over changes to your client application, execution of arbitrary code on client systems, and leakage of sensitive information to third parties. Its examples include the 2018 Ticketmaster incident and ClearSky's Magecart investigation of payment-data theft.
Build the inventory page by page, starting with checkout, login and admin. For each script, record the URL, the business owner, the reason it exists and how it arrives. OWASP describes three delivery routes: vendor code pasted into the page, a <script src> pointing at the vendor, and an indirect request through a tag manager.
The tag manager is the least visible. It can return scripts from several vendors, and staff can change what it returns through a web interface without touching your code. Changes go live on the next page load, and the code is usually obfuscated.
The HTML source will not show those scripts. Open the developer tools, switch to the Network tab, walk through checkout and login, and list every host that serves a script.
Remove first, mirror second
Ask the owner of each entry whether it needs to be on that page at all. A marketing tag on a login page or admin panel rarely has a good answer.
For scripts that stay, OWASP lists in-house mirroring as a defence. You host a reviewed copy yourself, so a third party cannot alter it, and the vendor no longer receives the visitor's IP address, referrer or cookies. The price is upkeep: a mirrored copy misses the vendor's fixes, so someone must own re-reviewing and refreshing it.
Abandoned vendors are a separate problem. If the domain hosting a script expires because the vendor went bust or dropped the project, someone can re-register it and publish malicious code. A dead vendor in your inventory is a finding in itself.
Pin what you keep with Subresource Integrity
Subresource Integrity (SRI) lets the page state the hash a file must match. The browser compares the download to that hash before executing a script or applying a stylesheet, and returns a network error if it differs. MDN's SRI guide gives the generating command:
cat FILENAME.js | openssl dgst -sha384 -binary | openssl base64 -A
Prefix the output with sha384- and place it in the element:
<script src="https://cdn.example.com/script.js"
integrity="sha384-..."
crossorigin="anonymous"></script>
The markup has a few requirements:
- The
crossoriginattribute is required. The browser refuses SRI onno-corsrequests, so a tag without it will always fail. - The CDN must send an
Access-Control-Allow-Originheader. Many send*. - You can list several hashes. The browser uses only those from the strongest algorithm present (SHA-256, SHA-384, SHA-512 in ascending order) and accepts the file if any one matches, which lets you allow two versions during an upgrade. The W3C specification describes the same behaviour.
SRI fits files that stay the same until you change them. A script the vendor edits at will fails the check after each edit, and a tag manager container is that kind of script. Restrict who can publish to it and keep it off your most sensitive pages.
Restrict with Content Security Policy
SRI says what a given file must contain. A Content Security Policy (CSP) says where scripts may come from at all. MDN's CSP guide says to deliver it in the Content-Security-Policy header on all responses, not just the main document.
A starting point for a sensitive page lists the hosts you actually use:
Content-Security-Policy: script-src 'self' cdn.example.com; object-src 'none'
Once a script-src or default-src directive exists, inline JavaScript is blocked unless you enable it. MDN says to avoid 'unsafe-inline', because it defeats much of the purpose of a CSP. Where you need inline scripts, use a nonce: generated per response, unpredictable, inserted by a template. For static pages MDN suggests hashes instead, and external scripts then also need the integrity attribute.
OWASP states plainly that a data layer is not a sandbox, because tag-manager containers can run custom JavaScript and HTML. Restrict publishing access and review changes as application code.
Find the gaps without breaking the site
The Integrity-Policy header makes the browser block scripts that lack an integrity attribute or load in no-cors mode. Start with the report-only version:
Integrity-Policy-Report-Only: blocked-destinations=(script), endpoints=(integrity-endpoint)
The endpoint needs a matching Reporting-Endpoints header. Violations arrive as reports of type integrity-violation, naming the blocked URL. Pinned scripts drop out of the reports, so they are not a full script inventory.
When no reports arrive, MDN says blocking is safe to enable without user-facing breakage. A tag manager container you cannot pin keeps generating reports, so pages that load one stay on report-only. You can inspect the headers your pages send with our HTTP headers checker.
Where to start
- Build the inventory for checkout, login and admin pages from the Network tab, recording owner, purpose and delivery route for every script.
- Remove entries nobody can justify, especially on login and admin pages, and flag any vendor whose domain looks abandoned.
- Mirror files you are willing to own and re-review. Pin every script you keep: generate SHA-384 hashes, add
integrityandcrossorigin="anonymous", and test in staging. - Deploy
Integrity-Policy-Report-Onlyfor scripts and read the reports. EnforceIntegrity-Policyonly when every script on the page has anintegrityattribute, and keep tag-manager pages on report-only. - Test a
Content-Security-Policywithscript-srcandobject-src 'none'in staging, since it blocks inline scripts. Restrict who can publish in your tag manager. For an outside check, a penetration test can cover these pages.
