Overview
Threat actors have found a novel abuse vector for the npm ecosystem: publishing malicious HTML packages to npm and its mirror registries that impersonate Cloudflare CAPTCHA verification pages. When a victim visits a URL hosting one of these packages — via a CDN-hosted npm mirror like unpkg.com, jsdelivr.net, or cdnjs.cloudflare.com — they see what appears to be a legitimate CAPTCHA challenge. Completing the fake verification silently redirects the victim to an attacker-controlled website.
The technique exploits the inherent trust users place in npm mirrors, which are widely used to serve JavaScript libraries and assets at scale. Hosting phishing content on these high-reputation domains helps bypass URL filtering and gives the redirect chain the appearance of legitimacy.
How the Attack Works
Step 1 — Package Publication
Attackers create npm packages consisting primarily of malicious HTML/JavaScript rather than legitimate JavaScript libraries. These packages contain a landing page that closely mimics a Cloudflare Turnstile CAPTCHA or hCaptcha widget.
Step 2 — CDN Hosting via npm Mirrors
Once published to npm, the package's contents become accessible via multiple CDN-backed npm mirrors:
https://unpkg.com/<malicious-package>@1.0.0/index.html
https://cdn.jsdelivr.net/npm/<malicious-package>@1.0.0/index.html
These URLs originate from high-reputation domains that security tools and corporate proxies typically allow-list.
Step 3 — Victim Lure
Attackers distribute the CDN-hosted URL via:
- Phishing emails with links appearing to lead to a document or download
- Malvertising — ad networks serving the CDN URL as a landing page
- QR codes in physical or digital media
- SEO poisoning — getting the mirror URL to rank in search results
Step 4 — Fake CAPTCHA and Redirect
The victim sees a convincing Cloudflare CAPTCHA-style page. Upon "completing" the verification:
// Simplified malicious redirect logic
document.querySelector('.cf-turnstile-btn').addEventListener('click', () => {
window.location.href = 'https://attacker-controlled-site.xyz/payload';
});The redirect destination can serve:
- Credential harvesting pages (fake Microsoft 365, Google login)
- Malware downloads (disguised as required software or browser updates)
- Tech support scams — fake alert pages designed to call fraudulent support numbers
- ClickFix pages — clipboard-hijacking prompts that trick users into running malicious PowerShell
Why npm Mirrors Are an Effective Vector
| Factor | Why It Helps Attackers |
|---|---|
| High-reputation domains | unpkg.com, jsdelivr.net are routinely allow-listed |
| Free, instant publishing | No review required for new npm packages |
| Long cache lifetimes | CDN caching means content persists even after npm removal |
| HTTPS by default | Encrypted traffic hinders content inspection |
| No domain cost | Attackers pay nothing for hosting |
npm's open publishing model — a feature that made it the world's largest package registry — becomes a liability when abused for hosting non-code content. Unlike domain registration, npm package creation requires no identity verification and is effectively instant.
Mirror Persistence Problem
A particularly challenging aspect of this technique is mirror caching. When malicious content is removed from npm:
registry.npmjs.org— content deleted ✓unpkg.comcache — may serve cached content for hours or dayscdn.jsdelivr.netcache — similarly delayed invalidation- Third-party mirrors (China, EU CDN nodes) — invalidation not guaranteed
This means takedown of the npm package does not immediately remove all attack surfaces — cached versions on mirror infrastructure may continue serving phishing content well after the originating package is removed.
Detection and Defense
For Security Teams
-
Block direct end-user access to npm CDN mirrors — Unless your organization explicitly uses
unpkg.comorjsdelivr.netfor development, consider blocking or proxying these domains in your web proxy/CASB. -
Alert on redirects from npm CDN domains to unknown destinations — A user navigating from
unpkg.comorjsdelivr.netto a non-npm-related domain is a strong signal of this technique. -
Train users to recognize CAPTCHA abuse — Legitimate CAPTCHAs do not appear on npm CDN URLs. Any CAPTCHA encountered on a package mirror URL should be treated as suspicious.
-
Monitor phishing feeds for npm mirror URLs — Services like PhishTank, OpenPhish, and URLhaus increasingly track this technique.
For npm Users and Developers
-
Do not click links to npm CDN mirrors unless you explicitly expect a library — If someone shares a
unpkg.comorjsdelivr.netlink, verify it leads to a JavaScript file, not an HTML page. -
Report suspicious packages immediately — Use
npm reportor emailsecurity@npmjs.comto report packages that appear to host HTML phishing content. -
Audit your own packages — If you own npm packages, ensure they have not been compromised or typosquatted.
Suspicious URL Patterns
# Red flags — HTML content served from npm mirrors:
https://unpkg.com/<any-package>/index.html ← HTML, not JS
https://cdn.jsdelivr.net/npm/<pkg>/captcha.html ← explicit phishing indicator
https://unpkg.com/<pkg>@1.0.0/verify.html ← "verify" pages from npm mirrors
Broader Supply Chain Implications
This attack joins a growing list of npm ecosystem abuses:
- Typosquatting — Packages with names similar to popular libraries
- Dependency confusion — Packages that shadow internal package names
- Malicious code injection — npm packages with embedded credential stealers
- HTML/non-code content abuse — This technique, using npm as a phishing host
Each abuse vector exploits the fundamental trust model of package registries: that content from a known, high-reputation registry can be served to end users safely. As threat actors continue to discover ways to weaponize this trust, security teams must apply the same scrutiny to CDN-hosted registry content as they do to any other user-facing web content.
Key Takeaways
- npm mirrors are being used as phishing hosts — Malicious HTML packages impersonate Cloudflare CAPTCHAs to redirect victims
- High-reputation domains bypass filters —
unpkg.comandjsdelivr.netare routinely allow-listed, making detection harder - Cache persistence extends the attack window — Takedowns from npm do not immediately clear mirror caches
- Block or proxy npm CDN access — Unless explicitly needed, end-user browsing to npm mirrors should be restricted
- Train users — No legitimate service delivers a CAPTCHA from an npm CDN URL