The compromises of debug, chalk, and axios looked, at the time, like three separate bad weeks for npm. Amazon's threat intelligence team now says they were one operation, run by the same North Korean crew, stretched patiently across more than a year. That single line reframes all three. These were not opportunistic criminals grabbing whatever package was easy to poison. They were a funded state group working a plan, and the plan targets the exact trust that modern software is built on.
Amazon assesses with medium confidence that the group behind the poisoning of typo-crypto, debug, chalk, and axios is the actor it tracks as Sapphire Sleet, also known as BlueNoroff. That crew has a long record of stealing cryptocurrency to fund the North Korean state. What changed is the target. Instead of phishing individual traders, it went after the packages those traders, and everyone else, install without a second thought.
One crew, three tiers of blast radius
The sequence reads like a rehearsal that went to production. In March 2025 the group trojanized typo-crypto, a small package that served as a testing ground. In September 2025 it moved to debug and chalk, two libraries buried so deep in the JavaScript dependency tree that Amazon estimates about a tenth of all cloud environments pulled the poisoned versions inside two hours. In March 2026 it reached axios, an HTTP client pulled more than 100 million times a week.
| Package | Compromised | Reach | Role in the campaign |
|---|---|---|---|
| typo-crypto | March 2025 | Small, niche | Testing ground |
| debug, chalk | September 2025 | ~1 in 10 cloud environments in 2 hours | Mass-reach proof |
| axios | March 2026 | 100M+ weekly downloads | Highest-value target |
Read that table as an escalation ladder, not a list. The group proved the technique on something small, proved reach on something ubiquitous, then aimed at one of the most-downloaded packages on the npm registry. The lesson for anyone choosing dependencies is uncomfortable. Popularity is not safety. It is a bigger target.
A signed, authentic update is the whole problem
Here is the part the checkmark crowd needs to sit with. Every one of these malicious versions was published through the legitimate maintainer's own account, after the group socially engineered the person who owns it. So npm provenance and package signing did exactly what they are designed to do. They confirmed the release came from the real maintainer, and it did. Signing proves who published a package. It says nothing about whether what they published is safe.
We made this same point when AsyncAPI's packages shipped malware with valid provenance. Sapphire Sleet is the industrialized version of that lesson. When the attacker owns the maintainer, the supply-chain attestation stops being a defense. It becomes a rubber stamp on the attacker's work.
The malware is split so nothing sees it whole
The tradecraft is built to beat the scanners teams lean on. Rather than dropping obvious malware into one package, the group spread it across several. In Amazon's account, one package hides the payload as an encrypted lump that reads like a settings file, another carries the key needed to unscramble it, and a third, pushed out weeks later, pulls the parts together and runs them. Each piece, examined on its own, looks benign. The malice only assembles at runtime.
That defeats point-in-time review and software bill-of-materials diffing, because the individual versions pass inspection the day they land. We watched the same delayed-detonation pattern when Mastra's packages passed inspection and turned hostile a day later. The payload also waits for a real target. Amazon says the code only fires during an actual install, ties itself to one-time environment values, and hunts for proof it has landed on a working developer or build machine before it does anything, so an analysis sandbox sees a quiet package. That is the same instinct behind npm malware that runs the moment you open the project rather than at install, when a scanner is most likely watching.
Where a captured-maintainer attack gets caught
If signing cannot help and static scanning is designed around, what does work? The detection has to sit where the code executes: the developer's laptop, the continuous-integration runner, the build agent. Those are the machines where the fetch-and-run stage finally shows its hand, and it shows it as behavior a defender can watch for. An install step that spawns a network connection to a freshly registered domain. A build process that reads an environment variable and then reaches out to an endpoint it has never contacted. A decrypt-then-execute chain kicked off by npm install. Amazon's indicators for typo-crypto include a lookalike registry domain, npmjs[.]store standing in for the real one, exactly the kind of signal host-level monitoring is meant to flag.
This is the argument for treating build infrastructure as production and watching it the same way. Managed detection that models normal host behavior and alerts on the deviation is what closes the gap the checkmark leaves open. It is the core of an endpoint detection and response posture that assumes the package is trusted and the behavior is not.
Pin your dependencies and watch your build host
Three concrete moves come out of this. First, pin dependencies to exact versions and hashes rather than floating ranges, so a poisoned update cannot roll into your build the moment it publishes. The group deliberately ships the payload-fetcher package later, which is precisely what a release cooldown is designed to blunt. Second, stop putting trust in the signing checkmark alone. Treat provenance as proof of origin, not proof of intent. Third, monitor the machines that run npm install, because that is the one place this campaign cannot hide. Amazon calls open-source security a job everyone shares. True enough, and the part that falls to you is the runtime.
North Korea is estimated to have stolen more than $2 billion in cryptocurrency in 2025, according to figures cited alongside the campaign. A group with that kind of return is not going to stop climbing the dependency tree. The next axios is already being groomed. The question is whether you will see it move.