tech, developers, and the code underneath

issue 069· news·

chalk and debug get compromised, and 2 billion weekly downloads flinch

A phishing email to a maintainer, eighteen packages, and a crypto-stealing payload in the browser.

A maintainer of several extremely widely-used npm packages — including chalk, debug, ansi-styles, and strip-ansi — was phished, and malicious versions of eighteen packages were published.

Combined weekly download counts for the affected packages are on the order of two billion.

the phish#

An email from npmjs.help — a lookalike domain — claiming the account required two-factor re-verification, with a link to a credential harvesting page that also captured the TOTP code.

The maintainer has written publicly about it. The email was well-constructed, it arrived at a plausible time, and the domain was close enough to pass a quick glance.

This is worth saying clearly: the target was a competent, security-aware, long-time open source maintainer. Phishing that captures a TOTP in real time defeats the second factor. The control that actually stops this is a hardware security key or passkey, where the authentication is bound to the origin and a lookalike domain simply cannot complete it.

If you publish packages, use a passkey or hardware key. Today. TOTP is not sufficient against this attack and has not been for years.

the payload#

Browser-targeted, not server-targeted, which is unusual and clever.

The injected code hooked window.ethereum and intercepted fetch and XMLHttpRequest, watching for cryptocurrency transactions and swapping destination addresses for attacker-controlled ones — selecting a visually similar address to survive a casual glance at the confirmation dialog.

Because these packages are ubiquitous transitive dependencies of frontend build tooling, the payload had a plausible path into a very large number of shipped bundles.

Actual losses appear to have been small. Detection was fast — within a couple of hours — and most builds during the window did not pull the affected versions.

why the damage was limited#

Three things, in order:

  1. Lockfiles. Most production builds resolve to pinned versions. A new malicious release does not enter an existing lockfile without someone running an update.
  2. Speed of detection. The community noticed within hours. Someone diffed the published tarball against the repository and the mismatch was obvious.
  3. Payload specificity. Targeting crypto wallets is narrow. A payload targeting build-time credential theft would have done far more damage.

That third point should not be comforting. The same access with a better payload would have been much worse.

the controls, again#

The same short list as every one of these:

  • Phishing-resistant auth on publishing accounts. Non-negotiable.
  • Trusted publishing via OIDC rather than long-lived tokens.
  • Lockfiles, committed, with exact versions in production.
  • --ignore-scripts in CI.
  • A cooldown before adopting new versions.

None of these are new. All of them are still not universally adopted, which is the actual story.

the structural observation#

chalk adds color to terminal output. It is about a thousand lines. It has two billion weekly downloads because it is a transitive dependency of nearly everything in the JavaScript ecosystem.

A thousand-line utility maintained by a volunteer sits in the trusted computing base of a substantial fraction of the world's software, and the ecosystem's security posture depends on that person's email hygiene.

That is not a criticism of the maintainer, who did nothing unreasonable. It is a description of a system that has grown a dependency structure nobody designed and nobody can now change.

The fix is not "fewer dependencies." The fix is publishing infrastructure where a single compromised human credential cannot ship code to two billion machines. The registry has to make that impossible, because asking every maintainer to be unphishable has failed for a decade.

Dom, September 9, 2025

get README in your inbox

One dispatch, no noise. Tech and developer news, plus the occasional long piece on the craft.

subscribe →