Supply Chain

The qix compromise (Sept 2025): how 2.6 billion weekly downloads got hit

One email, billions of downloads

On 8 September 2025, the npm account of a maintainer known as qix was compromised. Within a short window, malicious versions of around 18 extremely popular packages — among them chalk and debug — were published to the registry. Those packages together see over 2.6 billion downloads a week. For roughly two hours, anyone installing or building against the latest versions could have pulled in tampered code.

It is one of the largest npm supply-chain incidents to date, and the entry point was almost mundane.

How it happened

The maintainer was phished. He received an email that looked like a legitimate npm notice, spoofing the branding and warning that his two-factor credentials were about to expire, with a prominent 'update 2FA now' link. The link led to a convincing fake login page. With those credentials, the attacker took over the account and published the malicious releases under a trusted name.

No zero-day, no clever exploit of npm itself — just a well-made phishing email reaching one person who maintains code the entire ecosystem depends on.

What the malicious code did

The injected payload was a crypto-clipper: code designed to run in users' browsers and quietly swap cryptocurrency wallet addresses during transactions, redirecting funds to the attacker. By most accounts the actual financial damage was small, because the community spotted and removed the bad versions fast — the malicious releases were live for only about two hours before being pulled. The scare was the scale, not the loss.

Why this matters even if you never use those packages directly

The uncomfortable part of supply-chain risk is transitivity. You may never list chalk or debug in your own dependencies, yet they sit deep inside packages you do use. A tiny utility with billions of downloads is exactly the kind of thing that ends up in everyone's tree without anyone choosing it. That is the whole point of a supply-chain attack: compromise one widely-trusted link and you reach everything built on top of it.

The practical lessons

  • Use a lockfile and commit it. A package-lock.json pins exact versions and hashes, so a fresh malicious 'latest' does not silently land in your build.
  • Do not auto-update blindly. Let new releases age before adopting them; many supply-chain payloads are caught within hours, so a short delay is real protection.
  • Pin and review. Know what is in your tree, and treat a sudden new version of a deep dependency as something to look at, not wave through.
  • Verify what you actually ship. The end of this chain is the code that reaches your users' browsers — that is what an attacker is ultimately after.

None of this is a knock on the maintainer

It is worth saying plainly: a phishing email that convincing could catch anyone, and open-source maintainers carry enormous load for little reward. The takeaway is not to blame a person — it is that depending on shared code means your security partly depends on links you do not control, so you verify rather than assume.

Check what your site actually serves

You can pin and lock all you like, but the real question is what code ends up running on your live pages. An automated scan reads the scripts your site actually delivers to visitors and flags third-party resources running without integrity checks. Scan your site and see what you are really shipping.

Related reading

FAQ

What was the qix npm compromise?
On 8 September 2025, a phishing email tricked the npm maintainer known as qix into giving up his credentials. The attacker published malicious versions of around 18 popular packages, including chalk and debug — together over 2.6 billion downloads a week — containing a crypto-clipper. The bad versions were live for about two hours.
How can I protect my project from supply-chain attacks like this?
Commit a lockfile to pin exact versions and hashes, avoid auto-updating to brand-new releases, let updates age before adopting them, and review sudden new versions of deep dependencies. Crucially, verify the code that actually reaches your users' browsers rather than assuming the tree is clean.
I do not use chalk or debug directly — was I still at risk?
Possibly. Those packages sit deep inside many other dependencies, so they often end up in your tree without you choosing them. That transitivity is exactly why a compromise of a few widely-used utilities can reach projects that never list them explicitly.