Third-Party Scripts: The Code Your Marketing Team Added
A tag manager container is standing permission to run somebody else’s code on every page. Treat each script as a supplier: an inventory, a named owner, a review, an expiry date and a way out.
On This Page

Somebody in marketing trialled a heat-mapping tool in March. It went in through the tag manager, so no ticket was raised and nothing was deployed. The trial ended in April and the tag stayed. It still loads on every page, including the one with the payment form, from a domain nobody at the company recognises, under an account belonging to a person who left in June.
That is an ordinary situation, not a scandal, and it is worth naming plainly. Every third-party tag on your site is remote code execution that somebody consented to. A script loaded from another company’s domain runs with exactly the privileges your own code has. It can read the whole page, read what a visitor types before they submit it, rewrite links, fire network requests to anywhere, and load further scripts you never saw.
This is the design of the web, not a defect in it. The browser has no way to express "this script may draw a heat map but may not read the field labelled card number". Third-party script risk therefore has nothing to do with whether a vendor is trustworthy today. It has to do with what you have permanently granted, to whom, and whether anybody would notice if it changed.
The answer is not to ban tags. Marketing needs measurement, and a security posture that stops work gets routed around within a fortnight. The answer is to treat each script as a supplier with an owner, a purpose, an expiry date and a documented way out, and to make the approval fast enough that nobody has a reason to bypass it.
Every tag is code you did not write
Once a script executes in your page it has the same reach your application does. It reads and rewrites the document. It reads cookies not marked HttpOnly, along with local storage. It can attach a listener to every keystroke in every input. It can send whatever it collects to any host that will accept it. None of that requires a compromise. That is a normal script doing normal script things.
The part that surprises people is the chain. Your page loads a vendor. That vendor’s file loads a second vendor. The second one loads a third, usually an advertising partner. You approved the first and inherited the rest, and nobody sends you a notice when the list changes. Forms are where this matters most, because a form is the point where a stranger hands over something worth having, which is the argument in a form is a triage instrument.
You are not choosing to trust one vendor. You are choosing to trust every vendor they trust, indefinitely, without being told when that list changes.
The realistic threat is rarely somebody targeting you specifically. It is a widely-used script being compromised upstream, a small vendor quietly acquired by a company with different data habits, or a file silently updated on a host you never pinned. Small organisations assume they are beneath notice, which is exactly the misunderstanding behind why small sites get attacked at all: the attack is on the script, and you are downstream of it.
Inventory first, opinions later
You cannot review what you cannot list, and almost nobody can list this from memory. Every engagement we start with an existing site begins here, because the inventory usually settles the argument on its own. People stop defending tags once they see how many are loading and how few have an owner.
Three passes that produce a real list
Pass one: open the network panel on the three pages that actually matter, which are usually the homepage, a form page and whatever page handles money, and write down every origin. Pass two: export the tag manager container and read it, including the tags marked paused, because paused is a setting and not a guarantee. Pass three: deploy a content security policy in report-only mode and collect what it reports for a week. The third pass finds the ones the first two miss, including scripts injected by other scripts. If you inherited the site, this is also the fastest way to learn what you actually own, which we covered in securing a website you did not build.
What each record holds
- Vendor and exact origin. The hostname the file comes from, not the marketing name of the product.
- An internal owner, by name. A team is not an owner. Ownership that survives a resignation is the whole point.
- Purpose, in one sentence. If nobody can restate the purpose without opening the vendor’s website, remove it.
- Pages it loads on. Most tags are scoped to every page by default and need to be scoped to a few.
- What it can see. Page content, form values, identifiers, IP address, or all of it.
- Consent category and contract. Which consent gate it sits behind, and whether processing terms exist and name sub-processors.
- Review date and removal instruction. Written on the day it goes in, while somebody still remembers how it was installed.
The inventory belongs with whoever does ongoing maintenance, not with whoever ran the campaign. Campaigns end. Tags do not, unless removal is somebody’s job.
Where third-party script risk actually concentrates
Not every tag deserves the same scrutiny. Sorting them by what they can reach turns a long list into a short one, and the short one is where review time should go.
| Script type | What it can read | What it can change | The failure to plan for |
|---|---|---|---|
| Tag manager container | Everything on the page | Anything, plus loading further scripts | A container becomes a permanent side door into production |
| Session replay and heat maps | Keystrokes, field values, page content | Little by design | Recording data you were never permitted to store |
| Chat and support widgets | Page content and whatever a visitor types | Their own interface, often the whole page | A vendor breach exposing conversation history |
| Advertising and remarketing pixels | URL, referrer, identifiers | Redirects and further pixel chains | Sub-vendors joining the chain without notice |
| A/B testing and personalisation | The page before the visitor sees it | The rendered page itself | An unreviewed variant shipping to everyone |
| Embedded forms and payment frames | The fields inside their own frame | That frame only, if it is a real frame | A neighbouring script reading the fields beside it |
| Font, icon and library hosts | Referrer and IP address | The file they serve, whenever it changes | A silent update to a file you never pinned |
The arithmetic is the same one that governs how many plugins is too many. Each addition is defensible in isolation and the total is not, because the risk is not the sum of the parts. It is the number of independent parties who can change your pages without asking.
Consent, contracts and the parts that are not optional
Anything not strictly necessary to deliver the page must not run before the visitor agrees to it, and tag managers make that promise very easy to break. A tag added by somebody who does not know the consent configuration fires on page load, before any banner is answered. That is not a design flaw in the tag manager. It is what happens when the cookie position you published lives in a document and the enforcement lives in a container nobody audits.
Contracts have the same gap. Your agreement with a vendor does not cover the third parties that vendor loads, unless it names them and commits them to the same terms. That is why the sub-processor clause is the one to read first, along with the deletion terms, and it is the subject of what a data processing agreement should say. The tags that feed lifecycle and automation tooling need the closest reading, because those are the ones deliberately carrying identifiable data rather than accidentally seeing it.
One caution about session replay in particular. Tools of that kind advertise masking for sensitive fields, and masking is usually configured by the person installing the tool rather than applied by default. Check what it captured, on a real page, with real form fields, before the trial goes anywhere near production traffic.
The controls worth the effort
Subresource integrity, where it applies
An integrity attribute carries a hash of the file you approved. If the file at that URL changes, the browser refuses to run it. It is a genuine defence against a host being compromised, and it works only where the file is pinned and immutable: a versioned library, a specific release of a widget. It does not work for tag managers, analytics loaders or anything designed to update itself, which is most of what marketing installs. Say that out loud rather than writing a policy requiring integrity everywhere, because a policy nobody can satisfy gets ignored in full rather than in part.
A content security policy that is actually enforced
A content security policy tells the browser which origins may supply code. Deploy it in report-only mode first, because it doubles as the discovery tool from the third inventory pass, then enforce it once the reports are quiet. Use nonces for inline script rather than blanket permission for inline execution. The honest limitation: a policy that allows a tag manager origin allows everything that tag manager can load, so a policy is only as tight as the loosest origin on it. It still converts "anybody may add anything" into "anybody may add something from an approved list", which is a real reduction and a change you can review.
Self-hosting and containment
Self-host everything that does not need to be remote. Fonts, icon sets and libraries gain nothing from a shared host and cost you an origin, a connection and an update you do not control. Pin versions and never point at a URL that resolves to the latest build. Where a script only needs to observe rather than participate, running it outside the main document, in a worker or a sandboxed frame, is worth testing, with the caveat that a fair number of vendor scripts break when they cannot reach the document directly.
Block a vendor’s domain in your own browser and reload the page that takes money. If the layout collapses, the form stops submitting, or the page hangs waiting on a request, you do not have a privacy question, you have an availability dependency on a company you have never spoken to. Fix that before you argue about tracking.
The performance bill arrives separately
Security review often ends with a nod and no action, so bring the other invoice as well. Third-party scripts compete for the same main thread that handles taps and clicks. Parsing and executing a large vendor bundle delays the browser’s response to the next interaction, which is exactly what responsiveness metrics measure, and it happens on the mid-range phone your visitor is holding rather than on the laptop the tag was tested on.
Loading a script asynchronously prevents it blocking the initial render and does not make it free. It still has to be fetched from another origin, with its own connection setup, and it still has to run. The pattern we see repeatedly is a page where every individual tag is defensible and the combined weight has quietly become the largest thing on the page. Measure with the tag and without it, using field data rather than one test on a good connection, and give each vendor a budget the same way you would give an image one.
An approval process people will actually follow
Here is the process we would put in place. It is deliberately short, because a heavyweight one produces shadow tags installed through whatever route is unwatched.
- A written request with a named owner. One sentence on what the script does and what question it answers. No sentence, no tag.
- State what it replaces. New measurement usually duplicates existing measurement. Removing the old one is part of the request, not a follow-up.
- A data review. What it can read, where that data is stored, which processing terms apply, and which sub-processors are named.
- A technical gate. Which pages it loads on, which consent category gates it, which policy origin it needs, and whether the file can be pinned with an integrity hash.
- An expiry date, always. Trials expire by default rather than by memory. Renewal is cheap; discovering a two-year-old trial is not.
- Record it on the way in. Inventory entry and removal instruction written at install time, while the knowledge still exists.
- Review on a schedule and delete without ceremony. Anything whose owner has left, or whose purpose nobody can restate, comes out. Reinstating a tag takes minutes.
A gate only works if somebody has the standing to refuse, which is the same organisational problem as deciding who can refuse to publish. Our parent company has written about that reviewing role directly in the reviewer’s pass. When the review runs, its output should look like findings rather than notes: each one with a severity, a priority and a recommendation, which is the shape a tool like Prooflin produces from an assessment.
What we would do in the first week
Three things, in this order. List every origin loading on the homepage, a form page and the page that handles money. Turn on a report-only content security policy and let it collect for a week. Find out who owns the tag manager account, and whether that person still works there. Most teams learn something uncomfortable inside a day, and none of it requires a project.
The concession, since this article has been asking marketing to accept friction. The process above genuinely slows things down, and there are weeks when a tag has to go live the same day it is requested. The workable answer is a fast lane rather than an exemption: same-day approval, scoped to specific pages, behind consent, with an expiry measured in weeks. Speed is not the enemy. Permanence granted by accident is.
The second concession is that none of these controls is complete. Integrity hashes do not cover self-updating scripts, a policy with a permissive origin protects less than it appears to, and a determined vendor can change behaviour without changing a filename. Partial controls still beat none, and the inventory alone catches more than the rest combined. If you want a second pair of eyes on what is loading, send us the page that matters most and we will tell you what is on it.
Common questions.
Why are third-party scripts a security risk?
Because a script loaded from another company runs with the same privileges as your own code. It can read the entire page, including what a visitor types into a form before submission, rewrite links, send data to any host, and load further scripts. The browser offers no way to grant a script partial access, so approving one approves all of that behaviour until somebody removes it.
How do I find every third-party script on my website?
Use three passes. Open the browser network panel on your most important pages and record every origin. Export the tag manager container and read it, including paused tags. Then deploy a content security policy in report-only mode for about a week and read the violation reports, which reveal scripts injected by other scripts and anything the first two passes missed.
What is subresource integrity and when does it help?
Subresource integrity is an attribute carrying a hash of the exact file you approved, so the browser refuses to run that file if it changes. It protects pinned, immutable resources such as a versioned library or a specific widget release. It cannot protect tag managers, analytics loaders or anything designed to update itself, which covers most marketing tags.
Does a content security policy stop marketing tags from working?
Not if it is rolled out properly. Start in report-only mode, which blocks nothing and reports every origin the page loads, then add the approved origins and enforce. Tags break only when an origin was never added. The realistic limitation is that allowing a tag manager origin also allows everything that tag manager loads, so the policy needs reviewing whenever the container changes.
Who should own approval for new marketing tags?
A named person with the standing to say no, sitting between the requester and production. In smaller organisations that is usually whoever owns site maintenance, with a data reviewer consulted for anything touching personal information. Ownership by committee fails, because tags get installed through whichever route is unwatched when a deadline is close.
How do third-party scripts affect site performance?
They compete for the same main thread that handles taps and clicks, so parsing and executing a vendor bundle delays the browser response to the next interaction. Loading a script asynchronously stops it blocking initial render but does not make it free. Measure the page with and without each tag using field data, and give every vendor a performance budget.
Facing this in your
own business?
Tell us where you’re headed — we’ll map the shortest honest route.