Clay Tech

"clay-works make things real"

translated from clazytech.com

Attackers Are Not After Your Service

A while back, a development partner asked me, “Just do these three things for me.”

npm, pip, bundler. The task was to switch each package-fetching setup to go through a proxy with security checks.

Honestly, my first reaction was, “Wait, do I actually need to do that too?”

Here’s the thing: I don’t have access to that partner’s GitHub. What we work on together is a small slice, and I can’t get into their repositories or the core of their cloud infrastructure. So I figured, even if something dangerous slipped in, the damage would fall on “the person with the credentials,” and it wouldn’t really concern an outsider like me — or so the reasoning went. It sounds plausible enough, even to me.

Even so, I decided to just do what I was told. The token had already been handed over, and it was just a matter of typing a few commands. I installed a deliberately prepared “malicious package” for testing, confirmed it was properly blocked with a 403, and the whole task was done in five minutes.

Then, after I finished, I started looking into it, and I gradually came to realize that my initial reasoning had completely missed the point.

So what exactly do these attacks steal in the first place?

The false comfort of “I don’t have access anyway”

My naive understanding was this: “Someone hijacks GitHub or AWS access and does whatever they want with the repositories or the cloud.”

News headlines mostly wear that same face too.

My opening thought — “I can’t get into my partner’s GitHub, so it’s not my problem” — and my other thought — “I barely use AWS, so being told ‘AWS keys are targeted’ doesn’t really land for me” — share the same root. I was trying to measure my own risk by access rights and service names.

That’s the trap. The moment you try to measure it that way, you get the judgment wrong. As I’ll explain below, the essence of this attack lies outside the question of “which service, and what permissions do you have on it.”

A worm named Shai-Hulud

In September 2025, npm saw its first observed “self-replicating worm.” Shai-Hulud (named after the desert sandworm). Starting from a small package called @ctrl/tinycolor, the infection spread to more than 500 packages.

The mechanism was nasty. Once a maintainer’s account was hijacked, the malware would automatically rewrite that maintainer’s other packages and republish them. Instead of a human planting infections one by one, it multiplied on its own. It was, literally, a worm.

Then in November, a more vicious second wave arrived. Shai-Hulud 2.0, whose repository description read “Sha1-Hulud: The Second Coming.” By some counts, 796 packages were hijacked, and their combined weekly download count exceeded 20 million. Some estimates put the number of affected repositories in the tens of thousands. It changed to fire at the pre-install stage, further widening the scope of damage. It even came with an aggressive bonus: if it failed, it would attempt to destroy the victim’s home directory.

And the story doesn’t end in the past tense. In 2026, this lineage flared back up as “Mini Shai-Hulud,” and in May it grew into an even bigger wave. In just 48 hours, on May 11–12, roughly 170 packages and more than 400 versions were poisoned, reaching even widely used namespaces like @tanstack, @mistralai, and @uipath. This time, it spread not just through npm but simultaneously through PyPI too, dragging the world of pip install into it as well. Later that month, another wave scattered more than 300 poisoned versions in just over 20 minutes, and new attacks were still being observed as of June. Making matters worse, some of these waves didn’t even bother stealing credentials — they hijacked the legitimate release pipeline and distributed malware “genuinely signed,” as authentic releases. Even the defensive line of “trust the publisher” has partly been broken.

I only heard about this quite recently myself. And that makes sense, because this isn’t a closed case — it’s still actively burning right now.

The essence isn’t “stealing a service,” it’s “stealing an environment”

This is the part I most wanted to write about.

The essence of this attack is not “targeting a specific service.” It’s “sweeping up every secret sitting in the environment, indiscriminately.”

I’m not a security expert, so what follows is secondhand knowledge, but roughly speaking, it works like this. First, it dumps the entirety of process.env (the list of environment variables) and picks up the tokens sitting inside. It directly reads cloud credential files lying around on disk. And the crowning move: it downloads and uses a legitimate tool called TruffleHog.

TruffleHog is, in its original form, a legitimate secret scanner meant for developers to check “did I accidentally leave an API key or password lying in my code.” It can detect secrets for hundreds of kinds of services. Attackers use it in reverse — that is, to exhaustively find every secret left in your environment, regardless of what service it belongs to. On top of that, it hits the metadata endpoints of AWS, GCP, and Azure to grab cloud workload credentials as well.

So the question I was asking from the start was wrong. It isn’t “will GitHub or AWS be targeted?” The correct framing is this: “Whatever was sitting in your .env or your CI gets taken, regardless of what service it belongs to.”

Stripe keys, database connection strings, Slack tokens, SSH keys — all of it is fair game. In a modern development environment, LLM API keys are probably stuck in .env too, and those get swept up all the same, as just another “secret that happened to be sitting there.” If it’s sitting there, it gets taken. That’s all there is to it.

This is where my opening reasoning falls apart. Sure, I can’t get into my partner’s GitHub. But the moment I run npm install on that partner’s project on my own machine, the danger sits on “my end.” Whether I have access rights or not has nothing to do with it. What gets stolen is my own token, carelessly sitting on my own laptop. Far from “safe because I’m an outsider,” my environment is precisely the entry point.

Not checking whether something exists — just taking everything

Here we need to flip our thinking.

We normally think about security “individually.” Protect this service’s token this way, store that API key that way. The image is one where you assign a countermeasure to each item, one by one.

But attackers don’t see it that way. They don’t bother checking, one by one, “is this key here, is that credential here.” They take the entire environment, wholesale. Sorting through the contents can happen later, at leisure, after the theft. So the mindset of “carefully protect only the important things” only works about half as well against someone who takes everything at once.

And the place packed fullest of all is CI/CD. Build pipelines typically hold production secrets, with strong permissions, carelessly. And npm’s install-time hooks are understood as an entry point that runs code with the permissions of the user doing the installing. A single npm install is all it takes — the pathway for extracting an environment’s secrets is, structurally, already laid out.

Vibe coding blows that entry point wide open

Lately, so-called vibe coding has become the norm. You ask an AI, “build me something like this,” and it picks out whatever libraries seem necessary, runs pip install or npm install on its own, and gets things to a working state. It’s fast, and it’s fun. I use it often myself.

But laid alongside today’s topic, this is fairly dangerous.

The pleasantness of vibe coding is propped up by “not scrutinizing things yourself.” Which package, at which version, with what install-time scripts bundled in — if you had to check each of those every time, you wouldn’t get that light, breezy feeling. You install things without paying attention, without really understanding, just to get going. That’s the core of the experience.

Now lay that alongside the earlier fact that a single npm install can trigger an infection, and that it spread to PyPI too. Even back when humans were installing things one by one, carefully examining each, everything still got swept away wholesale. Now something that isn’t even human clicks through it dozens of times, without paying attention at all. “Just install it for now” can itself become the single biggest weakness.

There’s an ironic punch line too. In the malicious commit slipped in during the TanStack wave in May, the attacker used a fake signature impersonating the official account of an AI coding assistant tool, and even rigged it to skip CI. The ease of leaving things to AI, and an attack that impersonates AI, meet in the very same place.

Not being an expert is exactly why I want to keep a basic posture

Honestly, I’m not a systems engineer, and I’m not a security specialist either. So everything explained above is only as far as my own research and understanding go, and anyone knowledgeable would probably find rough edges in it. Feel free to take it with a grain of salt.

Even so, there’s one thing about this whole affair that clicked into place for me. The comfort of “I don’t use that service” or “I don’t have access rights to get in there” — comfort grounded in access rights or service names — was entirely misplaced. If what needs protecting isn’t “a service” but “the environment itself,” then the very unit by which you take inventory has to change.

What CISA and various companies’ defense guides say in unison is simple but harsh: “Once infected, assume that every secret that was present in that development/CI environment has been stolen.” Don’t just rotate the keys for the service that was reported as breached — rotate every token that was sitting in that environment. Not feeling safe based on a service’s name seems to be the only reasonable posture.

In the end, where’s the weakest boundary?

Back to that opening request: “Just do these three things for me.”

That proxy was a good move, sealing off one entry point through which malicious packages could get in. In fact, the malicious test package was cleanly blocked.

But what truly needs protecting isn’t just the “entry point.” What needs protecting is the mountain of secrets itself, piled up carelessly on your laptop and your CI, without even a label bearing a service name.

The attacker isn’t targeting your service. What they’re targeting is the mess on your own desk.

The weakest boundary wasn’t the security design of the product. It was the developer’s own desk.


Reference links

This piece was originated and directed by Kuzuryu, and drafted by AI.


Originally published in Japanese at https://clazytech.com/2026/06/1621/. Translated with LLM assistance and reviewed before publication.