Supply chain attacks don't wait for CVEs

shad421 pts0 comments

Supply Chain Attacks Don't Wait for CVEs | Mendral<br>Five minutes. That's the gap we watched in production last week: a dependency was published to npm five minutes before a customer's PR commit, hadn't been indexed by deps.dev yet, and carried no advisory anywhere. A vanilla scanner would have let it through. Our agent flagged it because the publish timestamp was inside the active attack window.

That's the supply chain attack pattern now. By the time a CVE exists, the bad version has already pulled into thousands of CI pipelines. The publish-to-detection window is measured in hours, sometimes minutes. CI is the chokepoint, and the PR is where the decision has to happen.

The last twelve months on npm and Actions

A short timeline of what's actually shipped at developers in the last year. Every one of these is documented, with public writeups from researchers and emergency advisories from CISA or maintainers.

tj-actions/changed-files (March 2025). Attackers retroactively modified version tags on a GitHub Action used in over 23,000 repos. The injected payload dumped runner memory into workflow logs, exposing secrets in any public repo that ran the action during the two-day window. Tracked as CVE-2025-30066. CISA put out an emergency alert. Wiz traced the initial vector back to a separate compromise of reviewdog/action-setup (CVE-2025-30154), which had leaked a token used to push to the tj-actions repo.

Nx s1ngularity (August 2025). A malicious Nx version executed a post-install script that scanned the developer's filesystem, called locally installed AI CLIs (Claude, Gemini, q) for reconnaissance, and uploaded harvested secrets to a public repo created inside the victim's own GitHub account. GitGuardian counted 2,349 credentials from 1,079 developer machines. Wiz documented a second wave where the stolen GitHub tokens were used to flip private repos public.

chalk / debug / ansi-styles and 15 others (September 2025). A phishing email landed on the npm account of one maintainer (Josh Junon, "qix"). Within minutes, malicious versions of chalk, debug, ansi-styles, strip-ansi, supports-color, and 13 other packages went live. Combined weekly downloads: 2.6 billion. The payload was a cross-platform remote-access tool. Google later attributed the infrastructure to UNC1069, a North Korean threat actor.

Shai-Hulud worm (September-November 2025). The first self-replicating worm in npm. It harvested credentials on install, then used the stolen npm tokens to publish itself into more packages owned by the same maintainer. CISA tracked over 500 directly compromised packages and tens of thousands of malicious republished versions. Shai-Hulud 2.0 in late November added a step that hit AWS, GCP, and Azure metadata services to grab workload credentials, and pre-install execution to widen the blast radius.

Trivy (March 2026). Attackers poisoned 75 of 76 GitHub Action tags for Aqua's Trivy scanner. Any pipeline pinned to a compromised tag silently exfiltrated secrets. We had moved one of our customers, Anyshift, from Trivy v0.30.0 to v0.35.0 eleven days before. v0.35.0 was the only tag that wasn't poisoned. From their CTO, Stephane Jourdan: "Mendral saved our a** during the Trivy supply chain attack. The agent had pinned the secure version two weeks before, so we avoided rotating every key across our infra."

The pattern repeats. Phishing or token theft, malicious version published, malware activates on install, secrets out within minutes. The publish-to-takedown window is measured in hours (the chalk/debug versions were live for less than two), but that's enough time for thousands of CI pipelines to install the bad version. The blast radius is whatever was sitting in your CI environment: AWS keys, GitHub PATs, npm tokens, cloud workload credentials, signing keys.

Why scanners are reactive by design

Most supply chain tooling cross-references your lockfile against an advisory database. Dependabot, Snyk, the GitHub Dependency Review action, Grype, the older Trivy scans. They watch the GitHub Advisory Database, OSV, and the NVD. If a CVE exists for a version you pin, you get pinged.

That model works for vulnerabilities discovered through research. A logic bug in OpenSSL takes months to weaponize, and the advisory tends to land before active exploitation. It does not work for malicious-publish attacks. The advisory only exists after security researchers have spotted the bad version, written it up, and pushed it through coordinated disclosure. By that point, the attack has already happened.

There's also the lockfile drift problem. Your package.json declares loose ranges. Your package-lock.json pins exact versions. If those two disagree (and they often do), your scanner reads one source while CI installs from another. We see this constantly: production deps declared in the manifest that aren't in the lockfile, so the scanner never examines them. Audit gap. We saw it again in the customer PR last week.

CI is the...

version github from supply chain minutes

Related Articles