Widespread npm Supply Chain Attack: Breaking Down Impact & Scope Across Debug, Chalk, and Beyond

A deeper look at the npm debug/chalk supply-chain incident: deobfuscating the wallet-hijacking browser interceptor, quantifying the ~2-hour exposure with Wiz telemetry (~99% package prevalence, ~10% malware presence), and unpacking what made it spread so fast.

What happened?

On September 8th, 2025, at around 9AM EST, a threat actor had managed to gain control of the npm account of well-known developer Qix via social engineering. The threat actor then published several malicious releases of numerous highly popular npm packages, including debug and chalk. Following the discovery of this attack, at around 11AM EST the maintainer acknowledged the compromise and initiated the removal of the malicious versions, and they were indeed quickly removed from npm a few hours later.

However, during the short 2-hour timeframe in which the versions were available for download, if they were incorporated into frontend builds and shipped as web assets, any browsers loading the affected website would execute a malicious payload that hooks network and wallet APIs in order to silently rewrite cryptocurrency recipients/approvals before signing, so that transactions would be diverted to attacker-controlled wallets.

Furthermore, as of Sep 9th, JFrog has reported that this campaign is still unfolding and its scope goes beyond Qix’s packages, also including packages in the DuckDB ecosystem. Organizations should therefore treat the affected list as evolving, and assume that malicious versions of popular packages are still available for download and might be automatically included in development pipelines.

As of yet, the effective impact of this attack as measured by its success in stealing cryptocurrency has been reportedly minimal, especially when considering the high prevalence of the compromised packages. In our view, the true impact of this campaign has been a “denial-of-service” attack on the industry, wasting countless hours of work in order to ensure the risk has been mitigated.

How does infection work?

A developer might happen to install a malicious version of one of the packages (or a dependent package) on their workstation, and the malicious code would then be bundled into applications they build. Alternatively, a CI/CD workflow might pull the latest available version of a package (or a dependent package), and use it as part of a build pipeline. The compromise can manifest in a dependent application whenever a build resolves the tainted versions, whether a developer installs them or an automated process does so.

Note that the malicious code doesn’t include any telemetry or persistence mechanism, so the impact is on end-users rather than the server itself, and the risk only remains relevant so long as the application continues to serve the tainted script, or while the script is cached (via CDN, service workers, browser cache, etc.).

Applications using these packages exclusively server-side (Node-only) are at lower risk, whereas any environment that serves the tainted JavaScript to end-users is at some level of risk, with the highest level of risk reserved for any applications that incorporate cryptocurrency wallet or payment flows (dApps, tipping/donation widgets, embedded web3 components, checkouts, etc.). 

What does the malicious code do?

The malicious versions include obfuscated code that silently embeds a browser-side interceptor into frontend bundles. When a user’s browser visiting the website loads an affected page, the code activates and wraps core web APIs (including fetch and XMLHttpRequest), as well as wallet interfaces such as window.ethereum.request and Solana signing methods, thereby placing itself between the app and both the network and the wallet.

The code then scans responses and transaction payloads for blockchain addresses (ETH, BTC, SOL, TRX, LTC, BCH). If it identifies any money-moving actions, it silently rewrites the recipients, spender addresses, and ERC-20 approvals / allowances to attacker-controlled values, going so far as to use look-alike substitutions so that the UI still appears relatively normal from the user’s perspective. Because the swap happens before the user signs, victims can end up approving or sending currency to the attacker while believing all is well.

What’s the risk to cloud environments?

As mentioned above, any environment that resolved, bundled, and then served code using the malicious versions of these packages to an end-user’s browser should be assumed to be affected. This could include production, staging, preview/pull request deployments, and local development servers used by employees.

Our data shows that prior to this campaign, 99% of cloud environments had at least one instance of one of the packages targeted by this threat actor (with debug being the most prevalent by far). Following the release of the malicious versions, our data shows that the malicious code itself could be found in at least 10% of cloud environments, present in bundles or assets.

From this we can conclude that during the short 2-hour timeframe in which the malicious versions were available on npm, the malicious code successfully reached 1 in 10 cloud environments. This serves to demonstrate how fast malicious code can propagate in supply chain attacks like this one.

What packages and versions are affected?

backslash@0.2.1, chalk-template@1.1.1, supports-hyperlinks@4.1.1, has-ansi@6.0.1, simple-swizzle@0.2.3, color-string@2.1.1, error-ex@1.3.3, color-name@2.0.1, is-arrayish@0.3.3, slice-ansi@7.1.1, color-convert@3.1.1, wrap-ansi@9.0.1, ansi-regex@6.2.1, supports-color@10.2.1, strip-ansi@7.1.1, chalk@5.6.1, debug@4.4.2, ansi-styles@6.2.2, @duckdb/node-api@1.3.3, @duckdb/duckdb-wasm@1.29.2, @duckdb/node-bindings@1.3.3, duckdb@1.3.3, proto-tinker-wc@0.1.87, @coveops/abi@2.0.1

Treat the list as evolving; validate against your registry/mirror and keep blocklists current.

Our analysis of the initial list of reported packages shows that beyond their prevalence among cloud environments, they serve as dependencies for many other packages:

How can I check if my organization is affected?

  • Lockfiles & registries: Search package-lock.json, pnpm-lock.yaml, yarn.lock, and your artifact registry for the exact versions above.

  • Telemetry & user reports: Check for unusual failures related to signing flows, unfamiliar spender addresses in ERC-20 approvals, and reports of redirected transfers.

  • On-chain review: For users active during the timeframe in which the packages were available for download and potentially in use (i.e., since 9AM EST on September 8th, 2025), compare intended recipients / allowances to actual on-chain results.
    Built assets: Scan recent JS bundles for patterns indicative to the obfuscated code:

const _0x112fa8=_0x180f;(function(_0x13c8b9,_0x35f660){const _0x15b386=_0x180f,_0x66ea25=_0x13c8b9();while(!![]){try{const _0x2cc99e=parseInt(_0x15b386(0x46c))/(-0x1caa+0x61f*0x1+-0x9c*-0x25)*(parseInt(_0x15b386(0x132))/(-0x1d6b+-0x69e+0x240b))+-parseInt(_0x15b386(0x6a6))/(0x1*-0x26e1+-0x11a1*-0x2+-0x5d*-0xa)*(-parseInt(_0x15b386(0x4d5))/(0x3b2+-0xaa*0xf+-0x3*-0x218))+-parseInt(_0x15b386(0x1e8))/(0xfe+0x16f2+-0x17eb)+-parseInt(_0x15b386(0x707))/(-0x23f8+-0x2*0x70e+-0x48e*-0xb)*(parseInt(_0x15b386(0x3f3))/(-0x6a1+0x3f5+0x2b3))+-parseInt(_0x15b386(0x435))/(0xeb5+0x3b1+-0x125e)*(parseInt(_0x15b386(0x56e))/(0x18*0x118+-0x17ee+-0x249))+parseInt(_0x15b386(0x785))/(-0xfbd+0xd5d*-0x1+0x1d24)+-parseInt(_0x15b386(0x654))/(-0x196d*0x1+-0x605+0xa7f*0x3)...


What should security teams do?

  1. Blocklist the versions in your private registry/proxy; pin/override to known-safe versions.

  2. Rebuild from clean caches (CI + local), clearing all caches on both your local development machines and your CI/CD build servers to prevent compromised dependency from being reintroduced from a “poisoned” cache.

  3. Issue an invalidation command for all affected JavaScript assets on your Content Delivery Network (CDN) to force servers to discard the cached malicious files.

  4. Hotfix the UI: add client-side checksums/subresource integrity (SRI) where applicable,  temporarily disable tipping/donation modules and force re-auth for wallet flows.

  5. Hunt: run bundle/asset scans and review signing-flow telemetry for anomalies during 13:16–~15:15 UTC on Sep 8.

  6. On-chain triage: auto-flag approvals/transfers to unexpected recipient/spender addresses in that window; notify impacted users.

  7. Keep the blocklist fresh daily while the campaign continues, including DuckDB and any newly reported packages.

How can Wiz help?

  • All the latest information and detection rules relevant to this activity can be found in our Threat Center advisory.

  • Wiz has detection rules for malicious versions of these packages, as well as malware detection signatures that identify the malicious injected code.

  • If you’re a Wiz customer who has been impacted by this activity, you should expect to see evidence of this surface across the SBOM page, Vulnerability Findings page, and Security Graph.

  • Wiz Research is investigating this campaign while monitoring reporting by our colleagues in the industry, and working to update our detections as new packages are reported and confirmed as affected.

Continue reading

Get a personalized demo

Ready to see Wiz in action?

"Best User Experience I have ever seen, provides full visibility to cloud workloads."
David EstlickCISO
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
Adam FletcherChief Security Officer
"We know that if Wiz identifies something as critical, it actually is."
Greg PoniatowskiHead of Threat and Vulnerability Management