Cloud Security Office Hours Banner

Polyfill.io 2024

Step-by-step kill chain mapped to MITRE ATT&CK Cloud, sourced from official post-mortems and primary technical analyses.

February-June 2024 Critical CDN / Third-Party Script

Polyfill.io - The Domain Was Sold → Every Site Still Loading the Script Handed Over Its Users → Conditional Mobile Redirects to Scam Sites

Nothing was hacked. In February 2024 the polyfill.io domain and its associated GitHub account were sold to a Chinese company, Funnull, and by June the CDN was serving malicious code to every site that still had the script tag in its HTML. Sansec published the finding on June 25, 2024. The payload was a conditional mobile-only redirect to scam and betting destinations, gated to evade researchers - it did not fire for desktop browsers, for repeat visitors, or when developer tools were suspected. Widely reported as 100,000 affected sites, that figure was PublicWWW's default result cap; later analysis put the real number above 490,000. The supply-chain lesson here is not about packages at all. A <script src> pointing at someone else's domain is a standing grant of arbitrary code execution in your users' browsers, renewed on every page load, revocable by whoever owns that domain today rather than whoever owned it when you added the tag.

490,000+ sites - the widely quoted 100k was a tool's result cap
Nothing was exploited - the domain changed hands legitimately
Conditional payload - mobile only, evading researchers
May 2025: OFAC sanctioned Funnull and its administrator
📄 Sansec - Polyfill supply chain attack, the original research ↗ 📄 Censys - Digging into the web of compromised domains ↗
💰 Resource Development - Buy the Domain, Inherit the Trust
01
In February 2024 the polyfill.io domain and its GitHub account were sold to Funnull, transferring control of a script embedded in hundreds of thousands of websites
T1583.001 - Acquire Infrastructure: Domains

There is no intrusion in this chain, which is what makes it worth documenting. Someone bought a domain. The polyfill service had a genuinely useful history - it shimmed modern JavaScript features for older browsers, so developers added the tag and moved on, and the tag stayed in templates and themes for years after the browsers it supported had disappeared. Whoever bought the domain therefore inherited the accumulated trust of every one of those decisions without needing to compromise anything. Andrew Betts, who originally created the service and had not owned it for years, was blunt afterwards: no website in 2024 needed any of the polyfills the library provided, and sites should simply remove it.

February 2024: Domain and GitHub account sold to Funnull, a Chinese company
What transferred: Control of a script tag embedded across hundreds of thousands of sites
Exploitation required: None. A purchase
Why the tags persisted: Added years earlier, kept in templates long past usefulness
Original author's view: No site in 2024 needed the polyfills at all
Domain PurchaseInherited TrustFunnullT1583.001
📜 Execution - Arbitrary Code in Every Visitor's Browser
02
Because the script was loaded directly into each page, the new owner could serve any JavaScript, executing with the full privileges of the host site
T1059.007 - JavaScript T1195.002 - Compromise Software Supply Chain

A third-party <script src> executes in the host page's origin, which means it can read and modify the DOM, read cookies not marked HttpOnly, intercept form input including passwords and payment details, and issue authenticated requests as the logged-in user. The site's own security posture is irrelevant to this: TLS was intact, no server was breached, no dependency was installed. The response was served fresh from a domain the site had told browsers to trust, on every page load, and the site operator had no visibility into what those bytes contained on any given request. This is the same structural exposure that makes Magecart-style card skimming work, and it is why script inclusion deserves the scrutiny normally reserved for dependencies.

Execution context: The host page's origin, with its full privileges
Capabilities: Read and modify the DOM, read non-HttpOnly cookies, intercept forms, act as the user
Unaffected by: The site's own TLS, patching, server hardening, or dependency scanning
Delivery: Fresh from the third-party domain on every page load
Operator visibility: None into what was actually served
Third-Party ScriptSame OriginClient-Side Supply ChainT1059.007
🥸 Defense Evasion - Only Fire When Nobody Is Looking
03
The malicious payload was served conditionally - mobile devices only, with checks to avoid repeat visitors and anything resembling analysis
T1497 - Virtualization/Sandbox Evasion T1027 - Obfuscated Files or Information

Server-side conditional delivery is what let this run for months. The malicious response was returned only to mobile browsers, and suppressed for repeat visitors and for requests that looked like inspection, so a developer opening devtools on a desktop saw a clean, functional polyfill script. That defeats the obvious verification: you cannot check what a third-party CDN is serving by looking at what it serves you, because the operator decides per request. It also means the affected population and the observing population barely overlapped - the people who could have noticed were systematically excluded from seeing it, and the users being redirected to betting sites had no idea which site had sent them there.

Gating: Mobile devices only
Suppressed for: Repeat visitors, and requests resembling analysis or debugging
Result for a developer: A clean, working polyfill script
Why verification fails: The operator chooses the response per request
Payload: Redirect to scam and sports-betting destinations
Conditional DeliveryMobile OnlyAnti-AnalysisT1497
🌐 Impact - Half a Million Sites, and a Wider Web of Domains
04
Reported as 100,000 sites, the real figure exceeded 490,000; researchers linked the same operator to further CDN domains serving a much larger population
T1657 - Financial Theft

The 100,000 number that circulated everywhere was PublicWWW's default result cap rather than a measurement, and later analysis put the affected population above 490,000 sites - a useful reminder to check what a widely repeated figure actually counted. Researchers also connected the same operator to additional CDN and library domains, extending the potential reach considerably further. Because the payload was a redirect to scam and betting sites rather than a card skimmer, the direct harm was mostly to end users rather than site operators, but the access available was much broader than what was used.

Widely reported: 100,000 sites - PublicWWW's default result cap
Later analysis: More than 490,000 sites
Wider infrastructure: Additional CDN and library domains linked to the same operator
Harm delivered: Redirects to scam and betting destinations, aimed at end users
Harm available: Anything JavaScript can do in the host origin
490,000+ SitesMiscounted ScaleLinked DomainsT1657
🛠 Response - Suspension, Mirrors, and Eventually Sanctions
05
Namecheap suspended the domain on June 27, 2024; Cloudflare and Fastly stood up safe mirrors; in May 2025 OFAC sanctioned Funnull and its administrator

Containment came from infrastructure providers rather than from the affected sites, because the affected sites mostly did not know they were affected. Namecheap suspended the domain two days after Sansec published; Cloudflare and Fastly stood up trustworthy mirrors so operators who could not quickly edit their templates had somewhere safe to point; Google began warning advertisers whose landing pages loaded the script. In May 2025 the US Treasury's OFAC sanctioned Funnull and its administrator Liu Lizhi. Note what that response chain implies: hundreds of thousands of site owners were saved by registrars and CDNs acting on their behalf, which is not a control any of them could have relied on.

June 25, 2024: Sansec publishes the research
June 27, 2024: Namecheap suspends the domain
Mitigation offered: Cloudflare and Fastly safe mirrors; Google warned affected advertisers
May 2025: OFAC sanctions Funnull and administrator Liu Lizhi
Uncomfortable implication: Most affected operators were rescued rather than remediating
Domain SuspensionSafe MirrorsOFAC Sanctions

🛡 How to Defend Against This Chain

Self-host third-party scripts, or pin them with Subresource Integrity. An SRI hash on a <script> tag makes the browser refuse content that does not match, which would have broken this attack on day one for every site that used it - and broken the script cleanly rather than silently serving malware. SRI cannot be used with a service that intentionally varies its response, which is itself the argument for self-hosting instead. This site applies exactly that discipline to its own assets, described in how CSOH.org is secured.
Inventory every external origin your pages load, and delete what you no longer need. The polyfills had been unnecessary for years; the tags stayed because nobody audits script includes. Enumerate third-party origins across your templates, themes and tag manager, confirm each has an owner and a current reason, and remove the rest. Every one is a standing grant of code execution in your users' browsers.
Enforce a Content Security Policy, so an inherited domain cannot do whatever it likes. A strict script-src allow-list limits which origins can execute at all, and a connect-src policy constrains where injected code can send data. CSP would not have stopped polyfill.io itself, since the site had explicitly allowed that origin, but it constrains the payload's second stage and is the difference between a redirect and a full card skimmer.
Treat domain ownership changes in your dependencies as a security event. This attack is entirely a change of control. Watch WHOIS and registrar changes for the external origins you depend on, and be suspicious when a long-dormant open-source service suddenly changes hands or becomes newly energetic. The same instinct applies to maintainership changes in packages - the mechanism behind XZ Utils and event-stream.
Monitor from the outside, in the conditions your users actually experience. The payload only fired for mobile users, so desktop checks saw nothing. Synthetic monitoring from mobile user agents and real-user monitoring that reports unexpected navigations would both have surfaced this. If you only ever test as a developer on a laptop, you are testing the exact configuration the attacker excluded.
Check what a widely quoted number actually counted. The 100,000 figure was a search tool's result cap, repeated everywhere as a measurement, and the true figure was roughly five times larger. When scoping your own exposure, query your own estate rather than inferring it from a headline.

Related defense topics