npm Supply-Chain Compromise (chalk/debug + 17 packages, Sept 2025) — Motivates GitHub Dependabot 'Cooldown' Mitigation

npm Supply-Chain Compromise (chalk/debug + 17 packages, Sept (TL-2026-1714), also tracked as npm chalk/debug supply-chain attack, is a high-severity supply-chain compromise, first published 2026-07-27. It has no confirmed attribution, affects npm (open-source JavaScript ecosystem) chalk, maps to 21 MITRE ATT&CK techniques (T1027, T1041, T1056), and is covered by 9 detection rules and 35 indicators of compromise.

Key facts for TL-2026-1714

Threat ID
TL-2026-1714
Also known as
npm chalk/debug supply-chain attack, Qix npm account compromise, September 2025 npm crypto-clipper campaign
Severity
HIGH
Status
RESOLVED
Category
SUPPLY_CHAIN
First published
2026-07-27
Last reviewed
2026-07-27
Attribution confidence
LOW
Motivation
FINANCIAL
Target sectors
technology, software-development, financial-services
Target regions
Global
Detection rules
9
Indicators of compromise
35

Malware and tooling in npm Supply-Chain Compromise (chalk/debug + 17 packages, Sept

Malware and tooling: npm crypto-clipper (window.stealthProxyControl payload)

On 2025-09-08, a phishing attack against npm maintainer Josh Junon ('Qix') led to malicious, wallet-hijacking versions of chalk, debug, and 17 other packages (>2B combined weekly downloads) being published to the npm registry; the payload rewrote cryptocurrency transaction destinations in browser contexts. Help Net Security (2026-07-27) cites this incident as the motivating case for GitHub's new Dependabot 'cooldown' feature, which delays non-security dependency-update PRs (default ~3 days) to let the community flag malicious releases before auto-merge.

How npm Supply-Chain Compromise (chalk/debug + 17 packages, Sept works

On September 8, 2025 at approximately 13:00 UTC, an attacker sent a convincing 2FA-reset phishing email from the fraudulent domain npmjs[.]help to Josh Junon (npm handle 'Qix'), maintainer of the widely depended-upon chalk and debug packages. The email harvested Junon's npm credentials and a live TOTP code, giving the attacker full control of the account within minutes. At 13:16 UTC — roughly 16 minutes after compromise — the attacker began publishing trojanized versions of 18-19 high-traffic npm packages (chalk, debug, ansi-styles, ansi-regex, strip-ansi, wrap-ansi, slice-ansi, has-ansi, color-convert, color-string, color-name, color, simple-swizzle, is-arrayish, backslash, error-ex, supports-color, supports-hyperlinks, chalk-template), which collectively receive over 2 billion weekly downloads.

The injected payload was heavily obfuscated JavaScript that activated only in browser execution contexts (it deliberately no-opped in Node.js/server environments to reduce detection, occasionally throwing 'ReferenceError: fetch is not defined' during server-side builds — an incidental detection signal). In-browser, it hooked fetch(), XMLHttpRequest, window.ethereum.request, and Solana signing calls, then silently rewrote outbound cryptocurrency transaction recipients and token-approval targets to attacker-controlled wallet addresses across Ethereum, Bitcoin, Solana, Tron, Litecoin, and Bitcoin Cash. To evade visual inspection, the malware used Levenshtein-distance address substitution to select look-alike attacker addresses resembling the legitimate recipient, and specifically targeted ERC-20 function selectors for approve, transfer, transferFrom, and permit. A global object named window.stealthProxyControl was used to coordinate the hooked behavior, and a remote WebSocket endpoint (websocket-api2.publicvm[.]com) alongside two BunnyCDN-hosted domains (static-mw-host.b-cdn[.]net, img-data-backup.b-cdn[.]net) served as supporting infrastructure.

The community first raised suspicion around 14:16-15:20 UTC via Bluesky/GitHub; Junon publicly acknowledged the compromise at ~15:15-15:16 UTC. npm began takedown at 17:17 UTC, and all impacted chalk versions were removed from the registry by 19:59 UTC, with residual malicious versions of other packages cleaned up September 9. JFrog subsequently reported the campaign's scope extended beyond Qix's own packages. Despite the massive reach (an estimated 99% of scanned cloud environments contained at least one affected package pre-attack, ~10% contained the malicious code post-distribution), actual reported cryptocurrency theft was minimal given the short ~2-hour live window and rapid community detection.

Almost eleven months later, Help Net Security (2026-07-27) reports that GitHub has shipped a Dependabot 'cooldown' option (configurable via the `cooldown` key in `dependabot.yml`) that delays non-security dependency-update pull requests by a default window (the article cites 3 days) so that malicious package versions have time to be flagged by the community before automated tooling (including Dependabot itself) proposes the update. Security updates for known vulnerabilities bypass the cooldown. GitHub's Advisory Database recorded over 6,500 npm malware advisories in the year ending May 2026 (~18/day), underscoring that this chalk/debug incident is illustrative of an ongoing, high-frequency npm malicious-package problem rather than an isolated event.

MITRE ATT&CK techniques used in TL-2026-1714

Defense Evasion

T1027 Obfuscated Files or Information; T1140 Deobfuscate/Decode Files or Information; T1480 Execution Guardrails

Exfiltration

T1041 Exfiltration Over C2 Channel

Credential Access

T1056 Input Capture; T1621 Multi-Factor Authentication Request Generation

Execution

T1059 Command and Scripting Interpreter; T1204 User Execution

Command and Control

T1071 Application Layer Protocol

Collection

T1185 Browser Session Hijacking

Initial Access

T1195 Supply Chain Compromise; T1199 Trusted Relationship; T1566 Phishing

Impact

T1565 Data Manipulation; T1657 Financial Theft

Resource Development

T1583 Acquire Infrastructure; T1585 Establish Accounts; T1587 Develop Capabilities; T1608 Stage Capabilities

Reconnaissance

T1589 Gather Victim Identity Information; T1593 Search Open Websites/Domains

Affected products and versions in npm Supply-Chain Compromise (chalk/debug + 17 packages, Sept

  • npm (open-source JavaScript ecosystem) — chalk
    Vulnerable versions: 5.6.1
    Fixed in: registry-restored clean release post 2025-09-08 19:59 UTC takedown
  • npm (open-source JavaScript ecosystem) — debug
    Vulnerable versions: 4.4.2
    Fixed in: registry-restored clean release post 2025-09-09 cleanup
  • npm (open-source JavaScript ecosystem) — ansi-styles / ansi-regex / strip-ansi / wrap-ansi / slice-ansi / has-ansi
    Vulnerable versions: ansi-styles@6.2.2; ansi-regex@6.2.1; strip-ansi@7.1.1; wrap-ansi@9.0.1; slice-ansi@7.1.1; has-ansi@6.0.1
    Fixed in: registry-restored clean releases post cleanup
  • npm (open-source JavaScript ecosystem) — color-convert / color-string / color-name / color
    Vulnerable versions: color-convert@3.1.1; color-string@2.1.1; color-name@2.0.1; color@5.0.1
    Fixed in: registry-restored clean releases post cleanup
  • npm (open-source JavaScript ecosystem) — simple-swizzle / is-arrayish / backslash / error-ex / supports-color / supports-hyperlinks / chalk-template
    Vulnerable versions: simple-swizzle@0.2.3; is-arrayish@0.3.3; backslash@0.2.1; error-ex@1.3.3; supports-color@10.2.1; supports-hyperlinks@4.1.1; chalk-template@1.1.1
    Fixed in: registry-restored clean releases post cleanup

Remediation for npm Supply-Chain Compromise (chalk/debug + 17 packages, Sept

Patches

  • Pin dependencies to versions published before 2025-09-08 13:16 UTC or to the maintainer-restored clean releases published after the 2025-09-09 registry cleanup

Immediate actions

  • Audit package-lock.json / yarn.lock / pnpm-lock.yaml / bun.lockb for the compromised package@version pairs published 2025-09-08 13:16 UTC through 2025-09-09 cleanup
  • Delete node_modules and the local npm cache, regenerate lockfiles, and reinstall only verified clean versions of chalk, debug, ansi-styles, ansi-regex, strip-ansi, wrap-ansi, slice-ansi, has-ansi, color-convert, color-string, color-name, color, simple-swizzle, is-arrayish, backslash, error-ex, supports-color, supports-hyperlinks, and chalk-template
  • Rotate API keys, tokens, and secrets used in any build/deploy environment that installed an affected package during the exposure window
  • Block and alert on network indicators: npmjs[.]help, static-mw-host.b-cdn[.]net, img-data-backup.b-cdn[.]net, websocket-api2.publicvm[.]com, and IP 185.7.81.108

Workarounds

  • Use `npm ci` instead of `npm install` to enforce lockfile-pinned, reproducible installs and prevent silent adoption of a newly-published compromised version
  • Mirror critical/high-download dependencies through a private registry with pre-release vetting or the same cooldown-style delay Dependabot now offers natively

Longer-term hardening

  • Enable GitHub Dependabot 'cooldown' (dependabot.yml `cooldown` key) to delay non-security dependency-update PRs by a default window so malicious releases are more likely to be caught before auto-merge
  • Adopt Software Composition Analysis (SCA) scanning (e.g. Socket.dev, Semgrep, Snyk, Mend) in CI/CD with build-failure gates on known-malicious package versions
  • Require phishing-resistant / hardware-key MFA for npm accounts maintaining high-download packages
  • Rebuild and redeploy any application that shipped a bundle built during the exposure window, since server-side installs alone did not trigger the payload but bundled front-end code could have

Weaknesses (CWE) in npm Supply-Chain Compromise (chalk/debug + 17 packages, Sept

CWE-506, CWE-829

Timeline of npm Supply-Chain Compromise (chalk/debug + 17 packages, Sept

  • Attacker registers the phishing domain npmjs[.]help, later used to impersonate npm support.
  • All impacted chalk versions removed from the npm registry by 19:59 UTC.
  • npm registry operators begin takedown of the malicious package versions at 17:17 UTC.
  • Josh Junon publicly acknowledges the account compromise at approximately 15:15-15:16 UTC.
  • Community members flag suspicious obfuscated code in the new releases on Bluesky and GitHub between roughly 14:16 and 15:20 UTC.
  • First malicious package version published to npm at 13:16 UTC, roughly 16 minutes after account takeover; attacker proceeds to publish trojanized releases of 18-19 packages including chalk@5.6.1 and debug@4.4.2.
  • Fraudulent 2FA-reset email sent from npmjs[.]help to chalk/debug maintainer Josh Junon ('Qix') at approximately 13:00 UTC, harvesting credentials and a live TOTP code.
  • JFrog reports the malicious-package campaign extends beyond Qix's own packages; residual malicious versions of affected dependencies cleaned up registry-wide.
  • Security vendors (Sygnia, Qualys, Wiz, Sonatype, Semgrep, Aikido, StepSecurity) publish detailed technical breakdowns of the payload, IOCs, and blast radius.
  • Help Net Security reports GitHub has shipped a Dependabot 'cooldown' feature (configurable via dependabot.yml, default ~3-day delay on non-security update PRs) explicitly motivated by this incident, alongside GitHub Advisory Database figures of 6,500+ npm malware advisories in the trailing year (~18/day).

Sources cited for npm Supply-Chain Compromise (chalk/debug + 17 packages, Sept

Threats related to npm Supply-Chain Compromise (chalk/debug + 17 packages, Sept

Detection coverage for TL-2026-1714

As of 2026-07-27, Threadlinqs Intelligence publishes 9 detection rule(s) for TL-2026-1714 across Splunk SPL, Microsoft KQL and Sigma, covering 35 indicator(s) of compromise. The whole corpus is readable without an account; a free account unlocks full detection query text in Splunk SPL, Microsoft KQL and Sigma; paid tiers add raw indicator values, correlation and the MCP server. Threadlinqs MCP server · View plans.

Further reading

Threadlinqs Intelligence — Real-Time Threat Detection Platform

[ 0 threats ] [ 0 det ] [ CRIT: 0 ] [ HIGH: 0 ]
// threat_feed
$ sort --newest
Showing all threats

Latest Threats