Brevo's attacker hostname sat in a public certificate log for 19 days before the ClickFix injection
Certificate Transparency records the attacker's hostname on a Brevo domain at 17:08 UTC on 25 August, 19 days and 22 hours before the first visitor saw a fake Cloudflare page. Brevo's list of changes does not mention certificate monitoring.
By Parminder Kumar Sharma · · 21 min read

The attacker's hostname was public for 19 days before anyone saw a fake Cloudflare page
Certificate Transparency is an append only public log. Every certificate a public certificate authority issues is written to it, and anyone can read it. I pulled the full record for sendibt1.com, a domain Brevo owns and uses for email open and click tracking, on 18 September 2026. It holds 432 log entries covering eight distinct hostnames.
Seven of those hostnames look exactly as you would expect a production domain to look: between 18 and 281 entries each, years of routine renewals. The eighth is cdn.sendibt1.com. It has one certificate, issued by Let's Encrypt at 17:08:10 UTC on 25 August 2026, valid until 23 November 2026. It appears nowhere else in the history of the zone.
Brevo's own post mortem puts the start of visitor impact at 15:01 UTC on 14 September 2026. The gap between the certificate and the first affected page is 19 days, 21 hours and 53 minutes. Brevo says separately that its investigation indicates the key was first misused in late August 2026, which is the same window from the other direction.
What this does not establish. A certificate log entry proves that somebody demonstrated control of a hostname in Brevo's DNS zone on 25 August. It does not name that person. It does not prove the Cloudflare credential was already stolen on that date, only that it or some other route to Brevo's DNS was in use. It does not prove Brevo was not watching. And it does not prove that any monitoring, however good, would have read one new subdomain in a zone of eight as hostile before it was used.
What it does establish is narrower and harder to argue with. The earliest public evidence of this incident existed, in a log designed to be read, for nearly three weeks. Brevo's list of changes after the incident covers its secret store, its Cloudflare audit events, its log pipeline, its asset integrity and its edge configuration review. It does not mention certificate monitoring.
What Brevo says happened, in its own numbers
On 14 September 2026 an attacker used a compromised Brevo Cloudflare API key to deploy a Cloudflare Worker on Brevo's account. A Worker runs at the CDN edge and can rewrite a response after it leaves the origin server and before it reaches the browser. This one appended a loader to the pages and scripts it was routed to.
Brevo describes the credential as a long lived Cloudflare API key with full account permissions, stored in application source code. With it, the attacker could create Workers, routes and DNS records across Brevo's zones. Brevo says this happened without triggering an alert.
The affected surfaces were pages on brevo.com, sendinblue.com, the login, account, my and onboarding hosts on brevo.com, and sibforms.com. Three JavaScript files that customers embed on their own sites were also modified in transit: the Brevo forms script, the Brevo Conversations widget and the Brevo SDK loader. Brevo states that app.brevo.com, the Brevo API, email sending and customer account data held in Brevo were not affected.
Brevo opened a security incident at 19:33 UTC and removed the Worker and its routes at 20:30 UTC. That is 4 hours 32 minutes from the start of impact to the incident being opened, and 57 minutes from opening it to stopping the injection. Independent verification that the affected pages and scripts were clean followed twelve minutes later.
Three exposure windows are on the public record for one injection. Computed from Brevo's post mortem and Sansec's observations.
| Window and source | Duration | What it actually measures |
|---|---|---|
| 15:01 to 20:30 UTC, Brevo headline | 5 hours 29 minutes | Pages on Brevo's own domains, from the Worker being routed to all of brevo.com |
| 16:07 to 20:30 UTC, Brevo detail | 4 hours 23 minutes | The three embedded JavaScript files, from the Worker being updated to append the loader to them |
| 16:05:18 to 20:12:53 UTC, Sansec | 4 hours 7 minutes 35 seconds | First and last malicious file Sansec actually observed being served |
The three windows are not contradictory, they are measuring different things, and the difference matters to anyone writing a customer notification. If your site embeds a Brevo script, the window that applies to you is the 4 hours 23 minutes one, not the headline 5 hours 29 minutes. If you are reconstructing what a monitoring system should have caught, the Sansec window is the observed one and it ends 17 minutes before Brevo's stated end time, which is consistent with the last malicious response being served before the route was torn down.
Reporting has not kept the distinction. BleepingComputer states the exposure window as 16:07 to 20:30 while also describing it as approximately five and a half hours. Both numbers come from Brevo, but they are not the same window.
Why the origin files stayed clean and the timestamps never moved
This is the part worth understanding properly, because it defeats the checks most organisations actually run.
A conventional web compromise modifies a file. The file's bytes change on disk, its modification time changes, a file integrity monitor notices, a deployment diff notices, a backup comparison notices. None of that happened here. The origin servers and the files on them were untouched. The rewrite occurred at the CDN edge, in the path between the origin and the browser, using a platform feature that exists precisely to rewrite responses.
Brevo puts it plainly:
Because the Worker rewrote responses at the edge and removed security headers such as Content-Security-Policy, our origin servers and files remained unmodified and standard integrity checks did not detect the change.
Sansec observed the consequence from the outside: the modified assets kept serving the same Last-Modified dates before, during and after the incident. A cache validator that never changes is the hallmark of this attack class. I checked the same file on 18 September and cdn.brevo.com/js/sdk-loader.js still reports a Last-Modified of 20 August 2024, unchanged for 759 days. That timestamp was as true during the injection as it is now, and it told you nothing.
The two controls that sit on the right side of that boundary are the only two that could have fired. A customer's own Content Security Policy governs its own pages, so the Worker stripping Brevo's header is irrelevant to it: a customer policy restricting script-src would have blocked the second stage load from an unrecognised host. Subresource integrity on the embedded script tag would have failed the hash and refused to execute the file at all.
Sansec's telemetry shows the first of those working. Its Content Security Policy monitor recorded 2,549 violation reports across 12 sites in and after the window. That is the only browser side measurement of this incident anywhere in the public record, and it covers twelve sites out of a population estimated in six figures.
The hundred thousand figure is a ceiling, not a count
Sansec reports that more than 100,000 sites embed the affected Brevo components. The figure comes from a PublicWWW source code search for sites containing brevo.com, sibforms.com or sibautomation.com. That is a count of sites carrying Brevo code, which is an upper bound on exposure. It is not a count of sites that served the malicious file, and it is certainly not a count of sites that were backdoored.
Nobody has published the number that matters. Brevo has not said how many customer sites loaded a modified script, how many visitors were shown the overlay, how many ran the command, or how many WordPress sites received the plugin. Sansec could not retrieve the plugin archive at all. The honest statement of scope is that the ceiling is six figures, the measured floor is 2,549 browser violations across 12 monitored sites, and the actual figure is unknown and currently unknowable from outside Brevo.
What the visitor was actually asked to do
ClickFix is a social engineering technique, not an exploit. Nothing is executed by the browser without the person's participation. The page writes a command into the operating system clipboard using the Clipboard API, then displays instructions that get the person to run it themselves.
Brevo's own description of the lure is specific enough to act on. Selected visitors saw a full screen Cloudflare branded page, sometimes appearing immediately after a genuine Cloudflare checkbox, asking them to press Win and R, then Ctrl and V, then Enter. Brevo states that following those steps ran a command placed on the clipboard by the script, which downloaded malware onto the visitor's Windows computer. Brevo also states the page was shown selectively, so most visitors and repeat visits saw nothing. Sansec adds that the malware did not activate for crawlers, developers and automated scanners.
Microsoft's analysis of the technique explains why the Windows Run dialog is the preferred destination rather than a terminal: the threat actors are relying on people not knowing what it is, and a terminal warns when pasted text contains multiple lines. Microsoft also names the artefact that makes this investigable after the fact. Entering a command into the Run dialog writes it to the RunMRU most recently used registry key, which keeps a history of Run dialog executions and can be used to reconstruct user initiated activity. Microsoft notes it does not create an entry if the process execution fails.
That is the single most useful sentence in this whole story for a UK IT team. If you want to know whether anyone in your organisation fell for this on 14 September, RunMRU is where you look, and you do not need the vendor's cooperation to look there.
The second path was aimed at the site owner rather than the visitor. On WordPress sites embedding an affected Brevo widget, the script checked whether the browser was logged in as a WordPress administrator, and if so attempted to install and activate a plugin using that administrator's own authenticated session. Brevo confirms the attempt. Sansec identified the archive location but could not retrieve it.
BleepingComputer says it found the sample on VirusTotal and describes it as posing as a plugin called Web Media Optimizer while acting as a persistent backdoor and JavaScript loader: hiding itself from the plugin list, copying itself into the must use plugins directory for persistence, polling an attacker server for a base64 encoded URL to inject, keeping a backup copy of the last working URL, and carrying a hardcoded key that generates a valid administrator session without the password. I have not been able to verify that analysis against the sample myself, and neither Brevo nor Sansec corroborates it. Treat the plugin's capabilities as one publication's analysis of one sample, and the existence of the install attempt as established.
Connected, a continuation, or separate
This site covered Brevo's SAML cross tenant incident on 13 September. Brevo identified that flaw at 06:30 UTC on 10 September, closed the route at 08:30 UTC, and reported 138 accounts accessed, contacts exported from 43, six used to send phishing and 93 with no meaningful activity. Trezor reported that a resulting phishing message reached roughly 347,000 newsletter addresses.
Four days later came this one. The temptation, which the trade press has not resisted, is to call it the same attacker returning. SecurityWeek states that the attackers returned on 14 September. Brevo declined to answer BleepingComputer's question about whether the two incidents are connected.
The public record does not support the returning attacker story, and the certificate log is the reason. The Cloudflare foothold was established 15 days and 13 hours before Brevo identified the SAML flaw, not four days after it was closed. Whatever the relationship between the two intrusions, the second one's access predates the first one's discovery. Brevo's remediation for the SAML incident, which included signing out every user on the platform, would not have touched a Cloudflare API key hardcoded in source code.
What the record states about a link between the two Brevo incidents, and what it does not.
| Question | Stated on the record | Not stated |
|---|---|---|
| Same actor | Nothing. Brevo declined to answer the question | Any attribution, in either write-up |
| Same entry route | No. SAML scoping defect in the application, versus a credential in source code | How the Cloudflare key left Brevo's source code |
| Order of access | Cloudflare key first misused late August, SAML flaw identified 10 September | Whether the SAML investigation looked at Cloudflare credentials |
| Scope of the first response | Route closed, every user signed out, sessions reset | Whether any non application credential was rotated |
So: separate root causes, overlapping in time, with no published attribution either way. The framing that fits the evidence is not a second attack. It is one undetected foothold that outlived a full incident response at the same provider. That is a worse finding than a repeat offender, because a repeat offender at least implies the first response worked.
The question Brevo has not been asked, and should be, is whether the 10 September investigation examined credentials outside the application, and if it did, why a full permission Cloudflare key in source code survived it.
Whose deploy pipeline runs on your page
Here is the part UK site owners should sit with. A marketing platform's script tag is an open ended grant. You are not embedding a file, you are embedding whoever can change that file, plus whoever can change the path it travels down. In this incident the second group turned out to include anyone holding one API key.
The usual answers are subresource integrity and Content Security Policy. Both are real controls. Whether either is available to you is a question about the vendor's headers, not about your intentions, so I checked Brevo's three surfaces on 18 September 2026.
Whether subresource integrity is actually usable on Brevo's embedded scripts. Checked live on 18 September 2026.
| Asset | Can you pin a hash today | Why |
|---|---|---|
| cdn.brevo.com/js/sdk-loader.js | Yes | Returns access-control-allow-origin for a cross origin request, and the file is unchanged since 20 August 2024, 759 days |
| conversations-widget.brevo.com/brevo-conversations.js | No | Returns no CORS header, so integrity plus crossorigin cannot be used, and the file changed 28 hours before I checked |
| The second stage the loader fetches | No | The loader creates a script element at runtime and sets only src, with no integrity attribute |
The third row is the one that matters most and it is the one nobody mentions. I read the current sdk-loader.js source. It is 3,442 bytes, it finds your client key, and then it builds a script element pointing at sibautomation.com/sa.js with your key appended, and injects it. No integrity attribute, by design, because the second stage is generated per customer.
Pin a hash on the loader and you have protected 3,442 bytes of glue code. The tracker that actually runs on your visitors' browsers arrives afterwards, from a different domain, with nothing verifying it. Subresource integrity on a loader is a control over the loader, not over the payload.
I confirmed the two published hashes myself. The sdk-loader.js served today is fe8447fd...aed09 at 3,442 bytes and brevo-conversations.js is 26166cd8...7ddca at 72,816 bytes, both matching the clean hashes Sansec published. Every malicious hostname in the cdn*.sendibt1.com family returns no DNS answer. Brevo's files really are clean. That is worth saying as plainly as the rest.
What would actually have caught it, and what would not
Each control against this specific attack. Assessed from the mechanism Brevo and Sansec describe.
| Control | Against this attack | Limit |
|---|---|---|
| File integrity monitoring at origin | No effect | Origin bytes never changed, by Brevo's own statement |
| Certificate Transparency monitoring | Would have raised a new hostname on 25 August | Raises an alert, not a verdict. An attacker with DNS write access can create more |
| Cloudflare audit log alerting on Worker, route and DNS changes | Would have raised the 14:28 deployment | Brevo says this did not exist. It is now on their change list |
| Scoped, short lived API tokens with IP and TTL limits | Reduces the blast radius of the same theft | Cloudflare documents these controls for tokens. They do not exist for the legacy global key |
| Your own script-src Content Security Policy in report only | Detects the unrecognised host immediately | Reporting only. Sansec's monitor caught 2,549 violations this way |
| Your own script-src Content Security Policy enforcing | Blocks the second stage load | Needs an accurate allowlist first, which is why report only comes first |
| Subresource integrity on vendor loaders | Blocks a modified loader | Does not cover what the loader fetches at runtime, and needs vendor CORS headers |
Cloudflare's own documentation is unusually direct about the credential class involved. A Global API key has access to all of a user's resources, has the exact same permissions as the user, is limited to one per user, and lacks the time window and IP range restrictions that API tokens support. Cloudflare states it is not recommended for new customers and encourages existing customers to migrate to tokens.
Brevo has not said which credential type was stolen, only that it was long lived, had full account permissions, and was hardcoded. Full account permissions and long lived is the signature of the legacy key, but I am inferring that, and Brevo has not confirmed it. Either way, the same account held DNS write, Workers deploy and route configuration for five apex domains. I confirmed on 18 September that brevo.com, sendinblue.com, sibforms.com, sibautomation.com and sendibt1.com all answer on the same pair of Cloudflare name servers. None of the five publishes a CAA record restricting which certificate authorities may issue for it.
# Step 1: deploy report only for a fortnight and collect what your pages really load.
Content-Security-Policy-Report-Only: script-src 'self' https://cdn.brevo.com https://sibautomation.com; report-to csp
Reporting-Endpoints: csp="https://your-collector.example.co.uk/csp"
# Step 2: when the reports are quiet, enforce the same list.
Content-Security-Policy: script-src 'self' https://cdn.brevo.com https://sibautomation.com; report-to csp
Reporting-Endpoints: csp="https://your-collector.example.co.uk/csp"
# Optional, once every script tag carries an integrity attribute:
Integrity-Policy-Report-Only: blocked-destinations=(script), endpoints=(csp)
The compliance angle for UK e-commerce
If you take card payments and your payment pages carry third party scripts, two PCI DSS requirements have been in force since 31 March 2025. Requirement 6.4.3 covers payment page scripts being authorised, checked for integrity and monitored for tampering. Requirement 11.6.1 covers detecting unauthorised changes to web pages. The Council's guidance is aimed at any entity processing card payments through e-commerce, including where an embedded iframe can affect the security of the payment.
Requirement 11.6.1 is worth re reading in the light of this incident specifically, because it covers HTTP headers as well as page content. A control that alerts when a security header disappears from a payment page is exactly the control that would have detected a Worker stripping a Content Security Policy header at the edge. Brevo's write up says that is precisely what happened.
Nothing here turns on Brevo being a payment platform. It is not. The point is that an attacker who can rewrite responses in the delivery path can strip headers as easily as inject scripts, and the requirement that anticipates that is already mandatory for a large share of UK online retailers.
What to do this week, in order
Take this with you
Ordered by what closes exposure fastest
- If you embed any Brevo script, work out whether an administrator browsed your own site's front end while logged in to WordPress on 14 September between 16:07 and 20:30 UTC. That is the only path to a site backdoor described anywhere in the record.
- Search web server access logs for that day for a POST to the WordPress plugin upload endpoint followed shortly by a plugin activation request, as Sansec advises. Then list the plugin directory on disk and compare it against what the admin screen shows, because the plugin described hides itself from that screen and copies itself to the must use plugins directory.
- If anything is found, rotate every WordPress administrator password and every application password, and assume session hijack rather than password theft, because the sample analysis describes a hardcoded key that mints an administrator session without the password.
- Query the Windows RunMRU registry key across your estate for ClickFix style entries dated 14 September, and treat hits as leads for endpoint triage rather than proof.
- Tell your own customers and staff what the lure looked like. Anyone who pressed Win and R, pasted and pressed Enter should have the machine treated as compromised, per Brevo's own instruction.
- Build a script inventory for every public page you own: every script tag, every domain it can reach, and a named owner for each. This is the artefact everything else depends on and almost nobody has one.
- Deploy a script-src Content Security Policy in report only mode with a reporting endpoint, and read the reports for a fortnight before enforcing.
- Add subresource integrity where the vendor serves CORS headers and the file is stable, and record explicitly where you cannot, and why. Do not record it as done when it covers a loader only.
- Turn on Certificate Transparency monitoring for every domain you own, alerting on hostnames you did not create.
- Inventory every long lived, broadly scoped API credential you hold with a CDN, DNS or edge provider. Replace with scoped, expiring tokens, restricted by IP where the provider supports it, and get them out of source code.
- Add the questions to your supplier review: which of your assets can I pin a hash to, do they carry CORS headers, what does the loader fetch at runtime, and do you alert on your own edge configuration changes.
The position
Brevo's post mortem is a good one. It publishes a minute by minute timeline, names the root cause without hedging, states clearly what was not affected, and tells customers to do specific things. That is better than most disclosures this year and it deserves saying, especially from a site that spent last week writing about the company's previous incident.
The gap is not in the writing, it is in the boundary the remediation draws. Every change on Brevo's list looks inward: the secret store, the Cloudflare audit events, the log pipeline, the asset integrity, the edge configuration review. All of it is worth doing. None of it would have fired on 25 August, when the only thing that happened was a certificate being written to a public log that anybody, including Brevo, could have been reading.
For customers the lesson is narrower and more uncomfortable. Every embedded script is a standing grant to a supplier's control plane, and the supplier's control plane now includes the CDN account, the DNS zone and whoever holds a key to either. Brevo's origin files were never touched and Brevo's integrity checks passed. The attack happened entirely in the space between those checks and the browser, which is the space almost nobody instruments.
So the question to put to a marketing platform, or to your own team about the scripts on your own pages, is not whether their files are signed or their certifications are current. It is this: if somebody rewrote your response after it left your building but before it reached my visitor, which of your controls would notice, and how long would it take? On this evidence the honest answer at Brevo was four hours and thirty two minutes, and the earliest available warning had been sitting in public for nineteen days.
Key facts
Sources
- PrimaryPost-mortem, Security Incident ClickFix: impact window, minute by minute timeline, affected surfaces, root cause, remediation and customer actionsBrevoaccessed 2026-09-18
- PrimaryWrite-up, Attacker gained access to client accounts: the 10 September SAML SSO scoping failure, 138 accounts, 43 exports, six phishing sendersBrevoaccessed 2026-09-18
- PrimaryForensics analysis: injected loader line, affected files and hashes, malware hostnames, CSP violation counts, certificate date and independent timelineSansecaccessed 2026-09-18
- PrimaryFull certificate history for sendibt1.com used to count distinct hostnames and date the single cdn.sendibt1.com certificateCertificate Transparency logs via crt.shaccessed 2026-09-18
- PrimaryGlobal API key documentation: access to all resources, full user permissions, one per user, no time or IP limits, not recommended for new customersCloudflareaccessed 2026-09-18
- PrimaryAPI token creation: per zone scoping, Client IP Address Filtering and TTL restrictionsCloudflareaccessed 2026-09-18
- PrimarySubresource Integrity: hash pinning, the CORS requirement for cross origin scripts, and the Integrity-Policy headersMDN Web Docsaccessed 2026-09-18
- PrimaryClickFix technique analysis: clipboard write, the Run dialog, the RunMRU registry artefact, hunting query and Group Policy hardeningMicrosoftaccessed 2026-09-18
- PrimaryEffective date of the e-commerce script requirements, 31 March 2025, and what 6.4.3 and 11.6.1 obligePCI Security Standards Councilaccessed 2026-09-18
- PrimaryInformation supplement announcement: scripts authorised, checked for integrity and monitored for tampering, and who the guidance applies toPCI Security Standards Councilaccessed 2026-09-18
- Reported byNews report and independent analysis of the Web Media Optimizer plugin sample, plus Brevo's non-answer on whether the two incidents are linkedBleepingComputeraccessed 2026-09-18
- Reported byNews report, used only for how the trade press framed the two incidents as one returning attackerSecurityWeekaccessed 2026-09-18
- Reported byThis site's 13 September briefing on the Brevo SAML cross tenant incident and the Trezor phishing that followedP.K. Sharmaaccessed 2026-09-18


