Why a Third-Party Script Tag Hands Its Vendor Control of Every Page It Loads On
A vendor script runs as your page, on every page, and the trust chain behind it runs through the vendor's CDN, DNS and credentials. What CSP and Subresource Integrity cover, and what they cost.
Every `<script src="https://vendor.example/widget.js">` on your site is a standing decision to run whatever that URL returns, as your page, for every visitor, forever. That is the entire security model of third-party JavaScript, and the Brevo supply-chain attack of 14 September 2026 is a clean demonstration of what it costs when the vendor's side of the bargain fails. Brevo's servers were never touched. A Cloudflare Worker at the edge appended a loader to three embedded scripts, and more than 100,000 sites served malware for hours.
What a Script Tag Actually Grants
The browser does not distinguish between code you wrote and code you included. A script loaded from a third-party origin executes in your page's origin, with full access to the DOM, to every form field a visitor types into, to cookies that are not marked HttpOnly, to local storage, and to the ability to load further scripts, open overlays, and redirect the page. It runs before the visitor has done anything and it runs on every page where the tag appears.
Marketing embeds tend to go into a site-wide template so that tracking and forms work everywhere. The vendor's script therefore runs on the login page, the checkout page and, on WordPress, inside the administrator's dashboard session. The Brevo loader used exactly that reach: it checked whether the visitor was a logged-in WordPress administrator and, if so, uploaded and activated a backdoor plugin using the administrator's own session. The visitor did nothing but load a page.
The Trust Chain Is Longer Than the Vendor
When you add a vendor's script tag, you are trusting more than the vendor's engineering team. The bytes that reach your visitor pass through a chain, and every link can substitute its own content:
- **The vendor's build and release process.** A compromised developer account or CI pipeline changes the file at the source.
- **The vendor's origin servers.** A web-server compromise changes the file at rest.
- **The vendor's CDN and edge configuration.** A Worker, snippet or transform rule can rewrite the response in flight while the origin stays clean.
- **The vendor's DNS.** Whoever controls the zone can point the hostname anywhere.
- **The vendor's cloud and CDN credentials.** One API key with broad permissions reaches all of the above at once.
Brevo's incident sat at the third and fifth links. A Cloudflare API key with full account permissions was stored in application source code, and an attacker used it to create hostnames and deploy a Worker that intercepted responses for brevo.com, sibforms.com and the embedded assets. Because the Worker also stripped the Content-Security-Policy header from the responses it rewrote, the vendor's own defence-in-depth went with it. The credential class that made this possible is the subject of "Why a Long-Lived CDN API Key Is the Most Dangerous Secret in Your Codebase."
None of these links is visible from the customer side. You can only decide how much of your page you hand over and how fast you would notice a change.
Why CSP Does Not Save You Here
Content Security Policy is the control most teams reach for first, and it is worth having, but its guarantee is narrower than people assume. A `script-src` directive restricts where scripts may be loaded from. It does not verify what those scripts contain. If `cdn.brevo.com` is on your allow list, then a modified `sdk-loader.js` served from `cdn.brevo.com` is, as far as CSP is concerned, exactly as legitimate as the clean version. The Mozilla documentation is explicit that CSP cannot defend against a script that is modified at an allowed origin.
CSP still did useful work on 14 September, in a different role. The injected loader pulled a second-stage script from an attacker hostname, `cdn2.sendibt1.com`, which was not on anyone's allow list. Sites with a reporting endpoint configured therefore received violation reports the moment the loader ran. Sansec's CSP monitor logged 2,549 reports across 12 sites during the window, which is how the injection was measured from outside Brevo. A `Content-Security-Policy-Report-Only` header with `report-to` costs nothing in breakage and turns a silent supply-chain modification into a timestamped alert, provided the modified script tries to reach somewhere new. A well-built payload that stays inside allowed origins would not trigger it, so treat CSP reporting as a tripwire, not a wall.
What Subresource Integrity Buys and Costs
Subresource Integrity is the control that actually addresses content rather than origin. You add an `integrity` attribute carrying a hash of the expected file, and the browser refuses to execute anything that does not match. The MDN reference gives the form:
```html <script src="https://cdn.example.com/script.js" integrity="sha384-<base64 hash>" crossorigin="anonymous"></script> ```
The hash is generated from the file itself:
```bash cat FILENAME.js | openssl dgst -sha384 -binary | openssl base64 -A ```
Supported algorithms are sha256, sha384 and sha512, and the `crossorigin` attribute is mandatory for cross-origin resources because integrity checking requires a CORS response. On mismatch the browser returns a network error and the script never runs. Against the Brevo Worker, every one of the three modified files would have failed the check and been blocked.
The cost is why almost nobody applies SRI to vendor loaders: the hash pins one exact version. Vendors like Brevo serve a loader at a stable URL precisely so they can push updates without asking customers to change their tags. Under SRI, every vendor release breaks the widget until you update the hash. That works for a pinned library whose upgrades you control, not for a marketing SDK the vendor updates on its own schedule, which is exactly the category that was hit.
Practical Options, Ranked by How Much Control They Return
- **Inventory every third-party script and where it loads.** Until you can say which pages carry which vendor tags, you cannot scope the exposure of the next Brevo.
- **Keep vendor scripts off pages that do not need them.** The administrator dashboard, login flows and checkout rarely need a chat widget. Removing the tag from those templates removes the highest-value targets from the vendor's reach.
- **Self-host a vendored copy where the vendor allows it.** A copy on your own origin is one you can hash, version and review. It shifts the update burden to you, which is the point.
- **Apply SRI to anything you can pin.** Versioned libraries, yes. Auto-updating loaders, only if you are prepared to treat every vendor release as a change you approve.
- **Run CSP in report-only mode with a collection endpoint** on every page, and review the reports. This is the cheapest detection you can buy for this class of attack.
- **Isolate widgets in sandboxed iframes** where the vendor supports it, so their code runs in a different origin and cannot read your page.
If a vendor script was modified and an administrator browsed the site during the window, the cleanup problem is different from the prevention problem. "How to Find a Hidden WordPress Plugin Backdoor After a Supply-Chain Injection" covers that side.
The Underlying Trade
There is no configuration that makes a third-party script safe, only a choice about what you let it touch and how quickly you would know it changed. Brevo's customers mostly had no answer to either question. The vendors will harden their edge accounts now; the controls above are the ones you actually own.