7 min readJohnny UnarJohnny Unar

The debug and chalk Hijack Was a Maintainer Identity Failure, Not a North Korea Story

Amazon tied the September 2025 npm hijack of debug and chalk to the same North Korean crew behind the axios compromise. The scary part isn't the attacker. It's the model.

ten months as a crypto scam

On July 29, 2026, Amazon Threat Intelligence published research attributing the September 2025 hijack of debug and chalk to the same North Korean group they later fingered for the March 2026 axios compromise. Read that timeline again. The debug and chalk poisoning happened in September 2025, sat in the public record for roughly ten months, and for most of that window it was written up as a garden-variety crypto-drainer, some injected code that swapped wallet addresses in the browser to skim transactions off anybody unlucky enough to pull the bad version. Everyone patched, everyone moved on, the postmortems got filed under supply chain hygiene and forgotten. Then the attribution landed and suddenly the story got a nation-state paint job, and a bunch of people who ignored it the first time started paying attention because now there's a flag on it. That reaction is exactly backwards. The interesting thing about this incident was never who did it. debug and chalk together carry north of two billion weekly downloads. chalk alone is a transitive dependency of a genuinely absurd fraction of the JavaScript tooling you touch every day, ESLint, Jest, half the CLI tools in your node_modules, all of it. When something that deeply embedded gets compromised, it does not matter whether the attacker is a bored teenager or a state-funded unit with a payroll and KPIs. The blast radius is identical. What made this possible was the same thing that would make it possible for a random opportunist, and that thing is boring, structural, and completely within your power to reason about.

one phished account, no redundancy

The entry point was a single phished maintainer account. Not a zero-day in npm, not a compromised CI runner, not a poisoned build cache. Somebody sent the maintainer of these packages a convincing email, harvested credentials or a session, and pushed a new version under a namespace that npm, your registry, your resolver, and your teammates all consider legitimately theirs. That is the whole attack. The reason it works is that the npm maintainer model treats publish rights as a property of an account rather than a property of a release, and most high-value packages have exactly one account that matters. There is no ownership redundancy, no second party who has to co-sign, no separation between the human who writes the code and the credential that ships it to two billion downloads a week. debug is maintained essentially as a solo project by someone doing the ecosystem an enormous favor for free, and I want to be clear that this is not a criticism of that person, phishing works on smart, careful people constantly and the burden should never have been on one volunteer to be an unbreakable identity fortress. The problem is that the system placed the entire trust boundary on a single inbox. When you npm install, you are extending transitive trust to every account that can publish anything in your tree, and you have no idea how many of those accounts have 2FA, whether it's phishable SMS 2FA or a hardware key, whether the maintainer reuses passwords, or whether they'll click the wrong link on a Tuesday. You are trusting hundreds of strangers' email hygiene.

your lockfile did nothing

The part that stings for teams who thought they'd done the work is that a pinned lockfile and a clean SBOM gave you no protection here, and understanding why is the actual point of this post. A lockfile pins versions and integrity hashes so that everyone resolves the exact same bytes, which is great against a mutated tarball or a typosquat sitting at a different name. It does absolutely nothing when the legitimate namespace publishes a new version, because from the lockfile's perspective chalk@5.x.y from the real chalk maintainer is chalk, full stop. The integrity hash matches the malicious tarball perfectly, because the malicious tarball is what got published under the real name. Your SBOM has the same blind spot. An SBOM tells you what you're running and where it came from according to the registry, and the registry cheerfully attests that this poisoned build came from the correct, verified, legitimate package. Every provenance signal you were relying on pointed at green. This is the trap. We spent years teaching people that reproducible builds and pinned dependencies and generated bills of materials would harden the supply chain, and they do harden a real class of attacks, but they all assume the namespace itself is trustworthy. The moment the trusted identity is the thing that got hijacked, every control downstream of that identity inherits the compromise and confidently reports success. Provenance is only as good as the account that produced it, and none of these tools were designed to answer the question that actually mattered, which was whether the human behind this publish was still the human you thought it was.

what would have contained it

There's a set of controls that wouldn't have prevented the phish but would have shrunk the blast radius from catastrophic to annoying, and they're all things you can act on this week. Verified publishing with trusted provenance, where packages are published from a known CI workflow via OIDC rather than from a laptop with a long-lived token, raises the bar because a stolen npm credential alone stops being enough, the attacker also needs to compromise the build pipeline that's allowed to mint the provenance attestation. npm's provenance support and the sigstore-backed attestations are the direction the whole ecosystem is crawling toward, slowly, and for any package your team owns you should turn it on now. Multi-party release signing is the bigger structural fix and the one the ecosystem keeps flinching away from because it adds friction, but a release model where two independent maintainers have to sign off before a version with two billion downloads goes live would have stopped this cold, because phishing one volunteer is easy and phishing two at the same time on the same release is a materially different operation. For the packages you consume rather than publish, the realistic control is dependency monitoring that flags new versions before they land in your build, a short quarantine window on new releases of critical dependencies, and alerting on maintainer or ownership changes. Tools like Socket and the newer registry proxies exist specifically to catch behavioral changes, a package that suddenly reaches for the network or reads env vars it never touched before, and that behavioral diff is often the only signal available when the identity and the hash both check out clean.

how we think about this at steezr

We build in this ecosystem every day, Next.js and React Native front ends, Go and Django services behind them, and every one of those projects has a dependency tree deep enough that we cannot personally vouch for every maintainer in it, so we've stopped pretending the goal is a perfectly trusted tree and started treating the tree as hostile-by-default and containing the damage instead. Concretely that means our critical deployments don't install straight from the public registry at build time, they resolve through a proxy that holds new versions for a review window and screens for behavioral drift, so a Tuesday-afternoon poisoning of a package we depend on doesn't hit production the same afternoon. It means we run provenance checks in CI and fail the build when a package that used to have attestation suddenly doesn't. It means for the internal tools and document pipelines we ship to clients, we keep the dependency surface deliberately small, because every package you don't depend on is an account that can't hurt you. None of this is exotic and none of it requires a threat intelligence team of your own. The debug and chalk incident is worth remembering not as the time North Korea got clever, they didn't need to be clever, but as the clearest possible demonstration that maintainer identity is an attack surface, that a single volunteer's inbox is load-bearing infrastructure for a huge slice of the software you ship, and that the controls you already trusted were quietly looking the other way. Design like the namespace can turn on you, because on this evidence it can.

Johnny Unar

Written by

Johnny Unar

Want to work with us?

Amazon tied the September 2025 npm hijack of debug and chalk to the same North Korean crew behind the axios compromise. The scary part isn't the attacker. It's the model.