Supply Chain Attacks on Developers Are the New Root Access
I did not start worrying about supply chain attacks because of a new CVE. I started worrying the day I noticed where the attackers were aiming. For twenty years the model was simple: the internet is hostile, the server is the prize, and you put a wall between the two. Firewalls, VPNs, bastion hosts, WAFs, hardened images, least-privilege IAM on the cloud account. We got good at defending the server.
Then we handed every developer a laptop with more access than the server, and we stopped watching.
That is the whole shift. Attackers are not trying to exploit your production boxes anymore. They are exploiting the person who has access to them. The developer machine holds SSH private keys, GitHub personal access tokens, npm publish credentials, kubeconfig files, Docker and Podman registry logins, cloud CLI credentials, and live browser sessions for Slack, Discord, and Teams. It is the vault. And the supply chain — a package manager that runs arbitrary code the moment you type install — is the cheapest lock to pick.
June 2026 was not a quiet month
This is not a forecast. It is a recap. The last few weeks produced a run of incidents that all point at the same target.
The one that should bother Linux people most is the campaign
Sonatype researchers named Atomic Arch. Attackers adopted
orphaned and abandoned AUR packages and injected malicious
code into the PKGBUILD and .install scripts. Hundreds of
AUR packages were compromised. The payloads went straight for
the vault: SSH keys, GitHub and npm tokens, browser cookies,
Docker and Podman credentials, cloud keys, and Slack, Discord,
and Teams session tokens. When a package was built or
installed as root, researchers reported persistence and an
eBPF rootkit capability. The Arch User Repository has always
run on trust. The attackers read the trust model and used it
exactly as designed.
On June 1, 2026, multiple npm packages in the
@redhat-cloud-services scope were compromised. Orca Security
named the attack Miasma: The Spreading Blight, and
StepSecurity documented it in parallel. The payload harvested
credentials, SSH keys, cloud tokens, cryptocurrency wallets,
and AI tool configurations. The root cause was depressingly
human: a Red Hat employee’s GitHub account was compromised,
and that was enough to push poisoned releases under a name
thousands of teams trust by reflex.
Back on May 11, 2026, a supply chain attack hit the TanStack open-source project through a breach of its GitHub Actions, according to Rescana’s analysis. The compromised Actions were used to publish malicious packages. The CI system that exists to ship code became the thing that shipped the attack.
Then there is axios. In 2026, Trend Micro, Phoenix
Security, and EndorLabs reported that axios v1.14.1 and v0.30.4
shipped with a hidden remote access trojan delivered through a
dependency named plain-crypto-js, after the maintainer
account was hijacked. Axios pulls more than 100 million npm
downloads a week. There is no meaningful difference between
“the maintainer pushed an update” and “the attacker pushed an
update” once the account is taken. The download counter does
not care who is at the keyboard.
On May 28, 2026, CISA issued an alert covering supply chain compromises that hit Nx Console and a set of GitHub repositories. The detail worth reading twice: threat actors used a prior compromise of Nx developer systems to compromise a GitHub employee’s device through a poisoned VS Code extension, and the payload scraped credentials from every major developer tool on the machine. Around the same window, GitHub rotated signing keys after a supply chain attack in which a payload ran on the next workspace open and pulled credentials from cloud providers and developer tools.
Six incidents. Different ecosystems — Arch, npm, GitHub Actions, VS Code. One target every time. Not the server. The developer.
The developer machine is the new vault
Sit with what is actually on a working engineer’s laptop, because the inventory is the whole argument.
There are SSH private keys, frequently without a passphrase
because passphrases are annoying and the agent caches them
anyway. There are GitHub personal access tokens, often scoped
far wider than the one repo they were minted for. There are
npm publish tokens that can push to packages other people
depend on. There are cloud CLI credentials sitting in
~/.aws/credentials, in the gcloud application-default file,
in the Azure CLI cache. There are kubeconfig files, and more
than a few of them carry cluster-admin. There are Docker and
Podman registry logins. There are browser sessions still
authenticated to Slack, Discord, Teams, and a dozen internal
dashboards. And increasingly there are AI tool configurations
holding API keys for OpenAI, Anthropic, and whatever else the
team wired into its agents.
That is more standing access than most production servers are ever granted. A production box usually has one role, one set of scoped credentials, and a blast radius someone bothered to think about. The laptop has all of them at once, and it is protected by a package manager that runs arbitrary code on install. We spent years arguing about whether to give a service account read or write. The developer machine has both, to everything, and it installs untrusted code for a living.
I have written before about treating agent tool access as an operational boundary rather than a convenience. The dev machine deserves the same respect and almost never gets it, because nobody filed a change request to make it privileged. It just slowly became the most privileged thing in the building.
The attack surfaces, ranked by how cheap they are to exploit
Not all of these cost the same to abuse. Rank them by effort and the picture gets clarifying.
npm preinstall and postinstall hooks
This is the cheapest one, which is why it keeps happening. npm
runs lifecycle scripts automatically on install. preinstall
runs before the package is even fully in place. This is not a
bug and it was never a bug — it is how npm was designed, so
that native modules can build themselves. The side effect is
that “I added a dependency” and “I executed a stranger’s code”
are the same action. The Miasma campaign leaned on
binding.gyp to get execution where postinstall restrictions
would have blocked it. The axios case showed you do not even
need a clever trick. Hijack the maintainer account and the
install hook does the rest, on every machine, on the next
npm install.
AUR orphan adoption
Nearly as cheap. The AUR lets anyone adopt an abandoned
package, and there is no review process for adoption. Once
you own the entry, the PKGBUILD runs as your user — or as
root if you build with sudo or makepkg -si, which plenty
of people do without thinking. Atomic Arch proved hundreds of
packages can be flipped silently this way. The attacker spends
nothing but patience, waiting for maintainers to drift away
from packages they stopped caring about years ago.
VS Code extensions
Also cheap, and badly underrated. Extensions run with full Node.js access on the developer machine. They can read the filesystem, open a terminal, and reach the network. There is no sandbox, no review gate worth the name, and a full trust model. The CISA alert showed exactly how far that goes: one poisoned extension was enough to compromise a GitHub employee’s device. The editor that every developer leaves open all day is a code execution surface with a marketplace in front of it.
GitHub Actions and OIDC
A little more expensive, because it usually requires
compromising a repository or its workflows first. The payoff
is why attackers pay the price. An Action with id-token: write can mint cloud tokens through OIDC, which means a single
compromised Action can hand out short-lived AWS IAM
credentials on demand. The CI runner already holds secrets,
tokens, and write access to the repository. The TanStack
breach showed this is not a thought experiment. Once the
pipeline is yours, you are not stealing one credential. You
are standing where the credentials are issued.
PyPI install hooks
Less common than npm, same class of problem. setup.py runs
on pip install, so a malicious package executes at install
time exactly like its npm cousin. The Red Hat incident is the
reminder that this is not a JavaScript problem. It is an
install-time-execution problem, and every ecosystem that runs
build scripts on install shares it.
Why the tools you bought don’t catch this
Here is the uncomfortable part for anyone who has spent a budget on a security stack. Most of it is aimed at the wrong moment.
DAST and SAST scan the code you wrote, not the dependency that
runs during install. SBOM tooling tells you what is in your
image — it does not tell you what executed on a developer’s
laptop at three in the afternoon when they ran npm install.
Container isolation does not save you when the secret is
mounted into the container, and a tool like Distrobox
deliberately exposes $HOME so the experience feels native.
Endpoint detection struggles to flag credential exfiltration
that rides out over the same HTTPS as a normal package fetch,
because to the network it looks like one more install talking
to one more registry.
The common thread is timing. The attack happens at install time. Most monitoring is runtime-only. By the time anything you bought is paying attention, the SSH key is already gone. I went through the gaps in the open-source scanning landscape in more detail in an earlier post, and the conclusion holds: these tools are useful for the problem they were built for, and that problem is not this one.
What actually helps, and what only looks like it does
I have been in this long enough to know the rationalizations. “We use a lockfile.” “We’re in containers.” “We have endpoint protection.” Each of those is true and none of them is the whole answer. So here are the principles I actually trust, stated plainly.
Pin dependencies and use lockfiles, and then actually honor
them. npm ci installs from the lockfile and fails on drift;
npm install quietly rewrites it. Run npm ci in CI and add
something like lockfile-lint so a poisoned resolution shows up
as a diff a human can reject, not a silent change nobody reads.
Use --ignore-scripts when you do not need build scripts.
It breaks packages that rely on native compilation, which is
the honest cost, but it closes the install-time execution path
for everything that does not genuinely need it. Decide per
project rather than leaving the default wide open.
Separate developer credentials from production credentials,
without exception. Production keys do not belong on a laptop
that runs untrusted code all day. If the only thing standing
between a hijacked npm package and your prod cloud account is
the file permissions on ~/.aws/credentials, you have already
lost; you just do not know the date yet.
Use short-lived credentials. AWS SSO, OIDC, a Vault-issued token with a fifteen-minute life — these change the math completely. A stolen credential that expires before the attacker reads their exfil log is a non-event. A long-lived API key is a permanent liability with your name on it.
Review AUR packages before you install them. Check the maintainer history, the last update date, and whether the package was recently orphaned and re-adopted. Atomic Arch hid in exactly the packages nobody was looking at. Looking is most of the defense.
Run CI/CD with least privilege. Do not hand an Action
id-token: write or repository write access it does not need.
The TanStack breach turned CI permissions into the attack.
Every scope you remove is a token the attacker cannot mint.
And the principle that reframes all the others: assume the developer machine is already compromised, and ask what your blast radius is. What can an attacker reach from that laptop right now, and what can you rotate in ten minutes? If the answer to the second question is “not much,” that is the work, and it is more valuable than any scanner you can buy.
One thing that does not help, despite how much people want it
to: containers do not save you if $HOME is mounted inside.
I like Distrobox and Podman and
wrote about that whole approach,
but isolation that mounts your home directory is not isolation
against this threat. The malware reads your secrets straight
off the mount. The container boundary is real for a lot of
problems. This is not one of them.
The old attack, aimed at a softer target
We spent twenty years building firewalls between the internet and our servers. Then we gave every developer a machine with more access than the servers, and protected it with a package manager that runs arbitrary code on install. The supply chain is not a new attack vector. It is the old one — exfiltrate the credentials, then walk in through the front door — just aimed at a softer target.
When I wrote that the bugs were always there and we simply were not looking hard enough, the lesson was about discovery. This is the same lesson wearing the other face. The attack surface was always there. The developer machine was always the vault. Attackers did not invent a new weakness in June 2026. They found the cheapest path to the access they already wanted, and the cheapest path runs through the install step we all treat as routine.
So here is the question I would put to any team before the next
npm install finishes: if your most senior engineer’s laptop
were quietly emptied tonight, would you know by morning — and
how much of what was on it would still be worth stealing by
the time you did?