The npm “chalk/debug” compromise: what happened, who’s exposed, and how to clean it up The npm “chalk/debug” compromise: what happened, who’s exposed, and how to clean it up

The npm “chalk/debug” compromise: what happened, who’s exposed, and how to clean it up

Attackers phished a well-known npm maintainer (Qix-). With that access, they pushed malicious updates to 18+ extremely common packages—including chalk, debug, ansi-styles, strip-ansi, wrap-ansi, color-convert, and others—collectively accounting for ~2B downloads per week. The payload is a browser-side interceptor: it hooks fetch, XMLHttpRequest, and wallet APIs (e.g., window.ethereum) to silently rewrite crypto addresses/approvals so funds or approvals go to attacker-controlled wallets. CLI usage wouldn’t normally trigger it; browser-embedded usage can.

Bottom line: if you built and shipped a web app from September 8 onward with one of the listed bad versions, assume risk and rotate secrets where appropriate.

Confirmed malicious packages & versions

Independent teams converged on the same set (some reports say 18, others “20+” as monitoring widened). The versions below are the malicious releases you must root out:

ansi-styles@6.2.2
debug@4.4.2
chalk@5.6.1
supports-color@10.2.1
strip-ansi@7.1.1
ansi-regex@6.2.1
wrap-ansi@9.0.1
color-convert@3.1.1
color-name@2.0.1
is-arrayish@0.3.3
slice-ansi@7.1.1
color-string@2.1.1
simple-swizzle@0.2.3
supports-hyperlinks@4.1.1
has-ansi@6.0.1
chalk-template@1.1.1
backslash@0.2.1

(Sources list the same set with minor ordering; some also mention color@5.0.1.)

Phishing domain used: npmjs.help (registered Sept 5, 2025).

How the malware works

  • Hooks core browser APIs: wraps fetch, XMLHttpRequest, and common wallet interfaces (window.ethereum, Solana methods) to inspect/alter requests & responses.
  • Pattern matches addresses: detects ETH, BTC (legacy/SegWit), SOL, TRON, LTC, BCH addresses.
  • Rewrites destinations/approvals: swaps legitimate targets with attacker addresses; can rewrite eth_sendTransaction, ERC-20 approvals (0x095ea7b3), transfers (0xa9059cbb), etc.
  • UI can still look “right” while the signed payload is poisoned.

This is not your usual “exfil secrets” loader. It’s a transaction manipulator aimed at web3 flows in the browser. If you only use these libs in Node/CLI context, the implant likely never executed—but if your build piped compromised code into any browser bundle, you have exposure.

Am I affected? Quick triage

  1. Search your lockfiles (package-lock.json, pnpm-lock.yaml, yarn.lock) for the exact bad versions above. If any match, you were exposed at build time.
  2. Check build timestamps: any production build between Sept 8–9, 2025 that resolved those versions should be treated as suspect.
  3. Look for browser usage: if affected packages landed in client bundles (not just dev/CLI), treat as high risk.

Immediate remediation (do this now)

  • Blow away caches and reinstall from scratch rm -rf node_modules npm cache clean --force npm ci # or: pnpm install --frozen-lockfile / yarn install --frozen-lockfile Ensure your lock file resolves to previous known-good or fixed versions. (Many maintainers and registries have already pulled the trojanized tags.)
  • Pin and verify
    • Keep lockfiles checked in.
    • Use npm ci/--frozen-lockfile.
    • Consider temporary resolutions/overrides to force safe versions.
  • Purge and redeploy
    • Rebuild all affected projects; purge CDN/build caches so no old bundles linger. (Vercel did this platform-wide; follow suit.)
  • Production monitoring
    • If you handle web3 in the browser, add runtime checks to block monkey-patched window.ethereum (e.g., verify provider methods’ source or seal the provider early).
    • Watch for anomalous wallet interactions and unexpected destination addresses.
  • Incident hygiene
    • If any real funds moved during the window, treat as compromise: notify users, rotate relevant API keys/secrets, and document timelines for auditors.

Hardening for next time (yes, there’ll be a next time)

  • 2FA + phishing-resistant auth for registry accounts (FIDO2 keys, not SMS/TOTP where possible).
  • Scoped, short-lived tokens for CI; keep publish tokens offline or behind approval gates.
  • Proactive allow/deny: use npm config set ignore-scripts true in CI for builds that don’t need install scripts; use tools that pre-scan packages before install. (Multiple vendors released emergency rules/detections within hours.)
  • SBOM + diff checks: generate SBOMs on every build and alert on unexpected dependency/version drift.
  • Bundle boundary checks: add unit/e2e tests that fail builds if window.fetch, XMLHttpRequest, or wallet APIs are wrapped unexpectedly in production bundles.

Why this incident was scary (and why it wasn’t worse)

The attacker chose ubiquitous, boring utilities—color parsing, ANSI helpers, small debug wrappers. That guarantees reach. But the payload focused narrowly on browser crypto flows, not API-key theft or generic RCE. If the same blast radius had targeted secrets, it could’ve been a bloodbath. We got lucky. Don’t plan on luck next time.

References & live trackers

Appendix: quick grep helpers

# Find any malicious versions in lockfiles
grep -E 'ansi-styles@6.2.2|debug@4.4.2|chalk@5.6.1|supports-color@10.2.1|strip-ansi@7.1.1|ansi-regex@6.2.1|wrap-ansi@9.0.1|color-convert@3.1.1|color-name@2.0.1|is-arrayish@0.3.3|slice-ansi@7.1.1|color-string@2.1.1|simple-swizzle@0.2.3|supports-hyperlinks@4.1.1|has-ansi@6.0.1|chalk-template@1.1.1|backslash@0.2.1' \
  package-lock.json pnpm-lock.yaml yarn.lock 2>/dev/null

# For monorepos:
find . -name "package-lock.json" -o -name "pnpm-lock.yaml" -o -name "yarn.lock" \
  -exec grep -HnE 'debug@4.4.2|chalk@5.6.1' {} \;