Observations

What went wrong, and what to do about it

Real breaches, each put through the same four questions: one control that worked, one that did not, one number worth watching, and what should have been done instead. Every entry cites a primary source, because the point of this section is that you can take it to a meeting.

NO. 24/Software / Supply chain/12 September 2026

Four hours, four hundred packages, and valid provenance on every one

Zscaler ThreatLabz, Tracking Shai-Hulud: Inside the ChainDrop NPM Worm

On 4 August 2026 a self-propagating worm entered npm through a compromised maintainer account. It pushed commits straight into source repositories, which triggered those projects’ own continuous integration pipelines to build and publish poisoned packages. Each infection steals the npm publishing token from wherever it lands, enumerates every package that token can write to, and publishes a poisoned version of each one. It reached more than 400 packages in under four hours, peaking at roughly one infected package per second, starting from keyv, cacheable, flat-cache and file-entry-cache.

What worked

Zscaler records nothing that npm, GitHub or anybody else did to detect, block or limit this while it was running.

What failed

Provenance, in the precise sense the ecosystem has spent years building. The poisoned packages carried "cryptographically valid SLSA Build Level 3 provenance" and valid trusted-publisher attestations, because they genuinely were built by the real project’s real pipeline from the real repository. Every link in the supply chain attestation was true. The commit at the start of it was not.

Zscaler states the conclusion plainly and it is the one to write down: "Do not treat SLSA/Sigstore provenance as proof of safety." Provenance answers where a package came from. It was never designed to answer whether the code is malicious, and an attacker who reaches the repository inherits the entire apparatus.

Then the automation. The release workflow "kicked in automatically", with no person between a pushed commit and a published package, which is what turned one compromised account into four hundred in four hours. And the tokens: every developer and every build runner that installed a poisoned version handed over its own publishing credentials, which is the mechanism that makes this a worm rather than an incident.

The number

4 hours

to reach more than 400 packages, at a peak of roughly one infected package published per second, every one of them carrying valid build provenance.

What to do instead

Put a delay between publish and consume. A release cooldown is the highest-value control against this whole class, because the worm ran its course in under four hours, and a policy of not installing anything published in the last day or two would have missed all of it. Zscaler recommends it and hardly anybody does it.

Then stop installing what you did not pin. Lockfiles applied strictly, npm ci rather than npm install, and a private registry proxy in front, so that a version published an hour ago cannot arrive in a build because a caret in a manifest allowed it to.

Then treat your build runner as a credential store, because that is what it is. Scoped, short-lived tokens instead of long-lived publishing credentials, restricted outbound network access from build environments, and pinned versions for every tool the build invokes. This spread because tokens were sitting where poisoned code could read them.

Then audit pull_request_target in your GitHub Actions workflows, which earlier waves of this campaign abused to steal a privileged token, and watch repositories that hold publish permissions for orphan commits and unexpected workflow files.

And change what provenance means inside your organisation. Treat it as an answer to where this came from, never as an answer to whether it is safe. If a policy anywhere says a signed package with valid attestation may skip review, this is the campaign that should change it.

NO. 06/Software / Remote access/4 September 2026

The remote access tool that had to revoke its own signature

AnyDesk public incident statement, February 2024

Attackers reached AnyDesk's production systems in late December 2023 and took source code along with private code-signing keys. AnyDesk detected it during an internal audit in mid-January, brought in CrowdStrike, revoked its certificates and shipped a rebuilt binary on 29 January, disclosing publicly on 2 February; within a day, more than 18,000 AnyDesk credentials were on sale on criminal forums.

What worked

They found it themselves. An internal security audit caught this, not a customer, not a researcher, not an extortion email, and on current numbers most organisations learn about their own breach from somebody else. They then did the expensive right thing rather than the cheap comfortable one: revoked the signing certificates and forced a client update, knowing that would break tooling for every customer and confirm the severity in public.

What failed

A private code-signing key was reachable from a production environment an intruder could get into. That key is not ordinary data; it is the thing that makes your customers' machines trust a binary, and once it leaves it can sign malware that every endpoint in your customer base will accept. The other failure is the arithmetic of the tool itself: AnyDesk exists to give someone remote control of a machine, so a compromise of AnyDesk is a potential compromise of every estate it is installed in, and that concentration was not reflected in how the signing material was held.

The number

18,317

AnyDesk portal credentials listed for sale within a day of the disclosure. Resecurity, who found the listing, attribute them to info-stealer malware on users’ own machines rather than to the breach itself, the rush to sell was the disclosure’s doing, not the source of the credentials.

What to do instead

Keep code-signing keys in an HSM and sign through a service that logs every request, so that a compromised build host can ask for a signature and still never possess the key. Treat that as a hard requirement rather than a maturity goal: it is the specific control that turns this incident from a supply-chain catastrophe into an expensive inconvenience. On the consuming side, inventory your remote access tools and know which vendor can reach your estate, because their incident is your incident, and the version pinning that protects you here has to be decided before their disclosure lands, not after.

Named for the doctrine distinction between a lesson observed and a lesson learned: a lesson is not learned until behaviour has changed and somebody has checked. Pretending otherwise is how the same finding turns up in three consecutive post-incident reports.