On 14 September 2026, for a window of a few hours, a marketing script embedded on tens of thousands of websites quietly started serving malware. No CMS was breached. No web server was compromised. The script tag those organisations had pasted into their templates months or years earlier simply returned something different that afternoon — and there was nothing on their own infrastructure to find.
The platform at the centre of it is Brevo, the email and marketing service formerly known as Sendinblue. Researchers at Sansec, who published the analysis, put the reach at up to 100,000 websites. Public scans find well over a hundred thousand pages referencing the affected infrastructure. Brevo has confirmed the compromise.
That is the part worth sitting with. Every one of those organisations had done nothing wrong on the day. They were compromised through a decision taken long before, by somebody else, in a codebase they have never seen.
What actually happened
The attackers held a Cloudflare API key with full account permissions. It was long-lived, and it had been hardcoded in application source code. Reporting indicates it may have been exposed as early as late August, with no malicious use detected at the time.
A key of that scope does not need an exploit to be devastating. It is a legitimate administrative credential, and everything done with it looks like normal platform engineering. With it, the attackers were able to create Workers, routes and DNS records without tripping any alarm.
Rewriting the response at the edge
Rather than touch Brevo's source systems, the attackers deployed a Cloudflare Worker that rewrote responses as they left the edge. The origin was never modified. A developer pulling the file from the repository would have seen clean code; a browser requesting it over the internet received something else.
The Worker affected Brevo's own web properties and, critically, three JavaScript files that customers embed on their own sites — the forms script, the conversations widget and the SDK loader, served from Brevo's CDN. It also stripped security headers, including Content-Security-Policy, on the way through.
An integrity control enforced by a header that the attacker controls is not an integrity control. The same position that let them rewrite the payload let them remove the thing that would have blocked it.
The active window has been reported as roughly 16:05 to 20:30 UTC on 14 September. The malicious subdomains stopped resolving the following day.
Two payloads, two audiences
The injected script behaved differently depending on who loaded it — and it deliberately avoided crawlers, developer tooling and security scanners, which is a large part of why it survived as long as it did.
ClickFix, for the ordinary visitor
General visitors were shown a fake Cloudflare verification page, followed by ClickFix-style instructions: copy this text, open a terminal or the Run dialog, paste it, press enter. The user performs the execution themselves, on a fully patched machine, in response to a prompt that appears on a site they trust.
We have written about this pattern before, in ClickFix to FileFix. It keeps working because it sidesteps every control built around downloading a file. There is no file. There is a human being following instructions.
A hidden backdoor, for the logged-in WordPress administrator
The second path is the more serious one. If a WordPress administrator visited their own site while logged in, the script rode their active session to attempt a plugin installation — no password prompt, no download, no consent dialog.
The plugin arrived as wm.zip and presented itself as "Web Media Optimizer". Once installed it:
- Hid itself from the WordPress plugin list
- Copied itself into the must-use plugins directory (
mu-plugins), where it loads automatically and cannot be deactivated from the admin interface - Called out to attacker infrastructure for JavaScript to inject into the site's own pages
- Carried hardcoded authentication, allowing the attacker to log in as an administrator at will
That is durable, self-concealing access to the site, obtained from nothing more than an administrator browsing their own homepage during a single afternoon's window.
Who is exposed
You are in scope if, on 14 September 2026, your site loaded Brevo's forms script, conversations widget or SDK loader from their CDN. The customer base is broad and includes very large consumer brands, so "we are not a marketing-led business" is not a filter here — these scripts are frequently added by a marketing team, not by engineering, and are rarely inventoried.
Brevo has stated that app.brevo.com, its API, its email delivery infrastructure and customer account data were not affected. This was an edge content-rewriting incident, not a breach of the platform's core. Separately, on 10 September, Brevo disclosed an unrelated SAML SSO issue affecting a small number of accounts.
What to do now
Treat this as an incident to rule out rather than a bulletin to file.
- Establish whether you loaded the script. Search your templates, tag manager and CMS for references to Brevo's CDN and form endpoints. Check the pages, not just the repository — third-party tags are often injected by a tag manager that no one has audited.
- Identify administrators who were logged in on 14 September. Cross-reference WordPress access logs against the 16:05–20:30 UTC window. These are the users at risk of the backdoor path.
- Compare the plugin directory on disk against what the admin screen shows. The plugin hides itself from the list, so the admin interface will not tell you. Look for anything created on 14 September, and inspect
wp-content/mu-pluginsspecifically — a legitimate site frequently has nothing there at all. - Rotate administrator passwords and invalidate sessions for anyone in scope, and review WordPress application passwords and API keys while you are there.
- Treat any endpoint where someone pasted a "verification" command as compromised. Full investigation, credential rotation for that user, and a review of what that machine had access to. An antivirus scan alone is not a conclusion.
- Audit your long-lived API keys. This is the uncomfortable part, because the failure that started this was not exotic. A full-permission key with no expiry, committed to source, is a common finding.
Hunting for it
A starting point for the network side, for estates with endpoint telemetry in Microsoft Sentinel or Defender:
let iocDomains = dynamic(["cdn10.sendibt1.com","yelahaye.surf",
"boiseno.club","glegchner.com","corralos.beer"]);
DeviceNetworkEvents
| where Timestamp between (datetime(2026-09-14) .. datetime(2026-09-17))
| where RemoteUrl has_any (iocDomains)
| project Timestamp, DeviceName, InitiatingProcessAccountName,
RemoteUrl, InitiatingProcessFileName
And for the ClickFix execution itself, which is behavioural rather than signature-based — a shell or script host launched directly from the desktop shell is the tell:
DeviceProcessEvents
| where InitiatingProcessFileName in~ ("explorer.exe")
| where FileName in~ ("powershell.exe","cmd.exe","mshta.exe","wscript.exe")
| where ProcessCommandLine has_any ("-enc","EncodedCommand","hidden",
"Invoke-WebRequest","iwr","curl","DownloadString")
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine
Tune the second query before you rely on it. In most estates it is quiet; in some, legitimate administrative habits will light it up, and that is worth knowing either way.
Indicators of compromise
Defanged for safe handling.
| Indicator | Type | Description |
|---|---|---|
| cdn10.sendibt1[.]com | Domain | Attacker-created subdomain on legitimate Brevo infrastructure, serving the second-stage script |
| yelahaye[.]surf | Domain | Attacker infrastructure |
| boiseno[.]club | Domain | Attacker infrastructure |
| glegchner[.]com | Domain | Attacker infrastructure |
| corralos[.]beer | Domain | Attacker infrastructure |
| wm.zip | Filename | Malicious WordPress plugin archive |
| Web Media Optimizer | Plugin name | Display name of the backdoor plugin; hides itself from the plugin list |
| wp-content/mu-plugins | File path | Persistence location — loads automatically, cannot be deactivated from the admin UI |
Infrastructure rotates. The behaviours above — an unexpected must-use plugin, a plugin on disk that the admin screen does not show, a browser-initiated shell — outlast any of these strings.
The lesson that outlasts this incident
Most organisations have a reasonably clear picture of the code they wrote and the servers they run. Very few have an equivalent picture of the third-party JavaScript executing in their users' browsers under their own domain. It is code they do not control, cannot patch, and in this case could not have inspected, because the malicious version existed only in the response and never in the repository.
Two structural points follow from that.
The first is that Subresource Integrity and Content-Security-Policy are the right controls and were not enough here, because the attacker was positioned at the edge and stripped the header on its way out. SRI on a versioned file would have helped; a CSP enforced from a position the attacker does not control would have helped. Both are worth doing. Neither is a substitute for knowing what is on your pages.
The second is about the shape of the detection. There was no alert to receive. The signal, if you had it, was an administrator's browser session doing something it never does, or a user's workstation launching PowerShell from Explorer at 17:40 on a Monday. That is behavioural, it is noisy, and it needs somebody watching who understands what normal looks like in your environment.
Our SOCs in Qatar, Jordan and the Philippines are manned around the clock, and this is precisely the category of event that gets found by an analyst asking why a process tree looks wrong — not by a feed arriving three days later with a list of domains that have already stopped resolving.