How a security team keeps third-party scripts under control across every property

Marketing, product teams and agencies add scripts faster than any review process can track them. How to replace inventory-by-asking with a browser-sourced script inventory on every property, alert rules routed to the SOC, and an approval workflow that leaves a record.

Published · Updated

The org chart is the problem. A security team owns the risk of every script running on every company property, and almost nobody who adds those scripts reports to security. Marketing has a tag manager. Product teams ship experiments. The agency behind the campaign microsites runs its own container on a domain you half-remember approving in 2024. Tag managers made script injection self-service, which was their entire point, and somewhere along the way the security review became optional, which was not.

The model that works has two halves. First, inventory by observing rather than by asking: a browser-sourced script inventory per property that records what actually executes, with integrity hashes and, on Scale, library versions matched against CVEs, deployed as one response header whatever the stack underneath. Second, a governance loop on top of it: alert rules for new script origins on every property and for unjustified scripts on payment pages, routed to the SOC, and a justification workflow that records who approved each script and why. CentralCSP provides both. The inventory is on every plan from €39.99/month (Start: 3 sites, 5 users, 250,000 reports a month).

Why inventory-by-asking fails

The classic approach is a questionnaire. Email every team that owns a property, ask for their script list, merge the answers into a spreadsheet, present it at the quarterly review.

Three things go wrong, every time. People list what they remember adding, not what is there. The heat-mapping trial from Q2 that nobody turned off does not make anyone’s list. Tag manager containers change weekly, and no change lands in the spreadsheet. And agencies answer for the properties they still think about, which is not the same set as the properties still serving traffic.

We have read plenty of these spreadsheets. The polite summary is that they describe an intention, not a website. The honest one is that the merge takes longer than the data stays true.

Inventory by observing: the browsers already know

Every script that executes, executes in a browser. CSP reporting lets those browsers tell you about it. Add the report-sha256, report-sha384 or report-sha512 reporting hashes under your script directives, point the Reporting-Endpoints header at the site’s managed endpoint (https://MyEndpoint.report.centralcsp.com, one subdomain per site), and each visitor’s browser reports the scripts it runs: origin, full URL, integrity hash and hash history, first and last seen, per page. No agent in the page, no crawler.

For a security team, the deployment story is the argument. Say the portfolio is a Next.js storefront, a WordPress marketing site, a legacy Java portal, a documentation site and whatever the agency built. Deploying an agent means five integration projects negotiated with five teams on five stacks. A response header is one line in each property’s server or CDN configuration, the same line everywhere, minutes per property. Each property becomes its own site in the workspace, with its own report cap, its own ingestion filter on which origins may report, and its own website roles, so streams never mix and the agency gets Viewer on its microsites and nothing else.

Because the data comes from real visitors, it covers what a crawler never sees: authenticated pages, geo-targeted variants, the script an A/B test serves to 3% of sessions. And every inventoried script carries its hash. On Scale, the Technologies view fingerprints that content to name the library and its exact version, matches the version against CVE databases with severity and affected range, and tags its lifecycle (up to date, outdated, dormant, deprecated), which is the client-side SBOM a review committee asks for a month later. Inline scripts are not analyzed. We wrote up that workflow in how to detect vulnerable scripts by CVE.

The governance loop, step by step

An inventory that nobody watches is a prettier spreadsheet. The loop is what turns it into governance.

Ground truth, continuously. The inventory replaces the quarterly questionnaire as the record of what runs where. When someone asks “do we load anything from that vendor”, the answer is a search, not a survey.

Alerting comes next. A new script origin rule per site is the loud one, and on Scale the pages declared as payment pages get the unjustified-script rule, so the checkout gets a tighter watch than the blog. Sixteen event types in all, across every report type the endpoint takes. Alerts go to Slack, Microsoft Teams, Google Chat, Telegram, email or HMAC-signed HTTPS webhooks whose JSON drops straight into Splunk, Datadog, PagerDuty, Opsgenie or Jira, which in practice means the SOC triages script changes in the queue it already works from. Cooldowns batch rather than drop, every delivery attempt is kept in a history, and rules are a REST resource, so the SOC’s own tooling can create them for a new property along with the site. This starts on Business at €129.99/month, with no cap on alerts. The routing details are in our piece on wiring CSP alerts into Slack, Splunk and PagerDuty, and the detection logic in detecting third-party script changes.

Then the approval artifact. On Scale (€349.99/month) and higher, where the PCI DSS module lives, each script on a declared payment page goes through a justification workflow: a business or technical justification per script, auto-validation rules so a routine hash rotation does not re-queue, a pending queue for anything new, and a dated change timeline (added, changed, removed, new origin) kept until the account is deleted, well past the 90 days the raw reports live. That record is the approval process: when the assessor, or the incident commander, asks who approved a script and why, the answer comes from a field someone filled in, not from archaeology in old Slack threads. For payment pages this maps directly onto PCI DSS 6.4.3.

Last, the team itself has to survive an audit. Workspace roles and per-site website roles (Viewer, Analyst, Manager, Admin, plus groups) are on every plan. SSO over SAML or OIDC and an exportable audit log come with Scale, and everything is stored and processed on OVH in France. If your review committee cares about data residency (banks do, we covered it in CSP monitoring for banks), that last point tends to shorten the meeting.

What this approach does not see

Worth being precise here, because vendors in this space rarely are. CSP observes loads and connections. It will tell you the moment a script’s bytes change, a new script appears, or a page starts talking to an origin it never contacted before. It will not tell you what an allowed, unchanged script does at runtime inside its own unchanged code.

In practice, most third-party compromises announce themselves exactly where identity monitoring looks: a modified file, a new origin, an unexpected addition. An attacker has to change something before the attack runs. But if your threat model demands behavioral analysis on one high-risk checkout, that is a separate tool for that one page, on top of the inventory, never instead of it.

Where to start

One property, a report-only CSP with the reporting hashes, one header. After a day of real traffic you will have a script list, and that list will contain something nobody on the team remembers approving. It nearly always does.

From there, the same header goes out property by property until the portfolio is covered. The Script Inventory page has the header syntax, and the 14-day trial on Start covers three sites and 250,000 reports a month, enough to inventory a few properties end to end.

Frequently asked questions

How can a security team get a JavaScript inventory across all company websites?

Do not ask the teams. Ask the browsers. Add the report-sha256, report-sha384 or report-sha512 reporting hashes to each property's CSP script directives and point reporting at a collector. Every visitor's browser then reports the scripts it executes, with origin, full URL and integrity hash. CentralCSP turns this into a per-site inventory on every plan, with library version identification and CVE matching on Scale, deployed as one response header per property regardless of the tech stack.

How do we stop marketing from adding scripts through the tag manager without security review?

You will not stop it, and fighting the tag manager is a losing argument internally. Instead, observe the outcome: a continuous browser-sourced inventory shows every script that executes, and alert rules (a new script origin rule per site, and on Scale an unjustified-script rule on declared payment pages, from CentralCSP's Business plan at €129.99/month with no alert cap) tell the SOC on ingest when something appears that nobody approved. Governance then becomes a conversation backed by data rather than a policy memo nobody reads.

What does a script approval process need to look like for PCI DSS 6.4.3?

Requirement 6.4.3 expects an inventory of scripts on payment pages, a business justification for each one, and a record that each script was authorized. CentralCSP's PCI DSS tooling covers this with a per-payment-page inventory and an authorization workflow that stores the justification per script. It is available on Scale plans (€349.99/month) and higher. The same artifact answers both the assessor and the internal question of who approved a script and why.

Can CSP-based monitoring detect a compromised third-party script?

It detects the change, which is where most compromises show themselves: a script's hash drifting, a new script appearing, an unexpected origin being contacted. A Magecart-style attack has to modify or add a script before it can act, and identity monitoring catches the modification. What it does not see is runtime behavior inside a script that is allowed and unchanged: CSP observes loads and connections, not what an unmodified script does with the DOM.