The first lie we tell ourselves is that a package is a thing we install. No. A package is a thing we execute and then spend the rest of the afternoon pretending that distinction was somehow philosophical.
May 2026 gave us another tidy little reminder courtesy of a BufferZoneCorp campaign across RubyGems and Go modules. The playbook is rotten in the most ordinary way: publish something that looks like a helper, let people trust it, then update it later into a credential vacuum. Ruby gems started harvesting environment variables, SSH keys, AWS creds, .npmrc, .netrc, GitHub CLI config, and RubyGems tokens. Go modules went full goblin: GITHUB_ENV, GITHUB_PATH, GOPROXY, GOSUMDB=off, fake go wrappers, and even an SSH persistence key tagged deploy@buildserver. Subtle as a brick. Effective as hell.
Maybe the most irritating part is that none of this is clever in the way startup goblins mean clever. It’s just patience and camouflage. The package is clean at first. It sits there looking like a harmless utility, a little cardboard box with a decent README and a fake moustache. Then update day arrives and it starts rifling through your machine like it owns the lease.
The trick is not magic
People keep talking about “malicious packages” like they’re weird edge cases. They’re not. They’re what happens when we treat registry names as identity and install hooks as ceremony.
RubyGems has extconf.rb. Go has init(). npm has postinstall. Cargo has build scripts. Every ecosystem invents its own little trapdoor and then acts surprised when someone climbs through it with muddy boots.
That’s why sleeper packages work so well. They exploit the social layer first. Humans scan names. Humans skim READMEs. Humans think “oh, this looks like a logging helper” and move on because the sprint review is in twelve minutes and nobody wants to be the paranoid idiot asking whether go-retryablehttp is maybe a knife with a GitHub profile.
It is. It absolutely is.
Your CI is not a monastery
The reason these attacks keep landing is that we keep stuffing secrets into build systems like they’re a family safe. They are not. They are a vending machine with root access and a panic button that nobody labeled.
If a malicious gem can read:
~/.ssh/id_ed25519~/.aws/credentials~/.config/gh/hosts.yml.netrc~/.npmrc
then congratulations, you did not “install a dependency.” You invited a burglar into your pocket.
And if a Go module can rewrite GOPROXY, flip GOSUMDB=off, mutate go.sum, or drop a fake wrapper into your path, that’s not supply-chain drama anymore. That’s a hostile workstation wearing a lanyard.
The worst part is how normal everyone has decided this should feel. “Use provenance.” Great. “Pin versions.” Sure. “Review install-time behavior.” Obviously. And yet the industry still keeps handing untrusted code a pile of credentials and hoping the README had good manners.
The actual fix, since apparently nobody enjoys one
No, this is not an argument against package managers. It’s an argument against acting like they are libraries instead of remote code execution with autocomplete.
The boring answers are still the right ones:
- make secrets tiny and disposable
- keep CI credentials scoped like you mean it
- block install-time scripts unless you have a damn good reason
- sandbox builds
- require provenance for updates, not just uploads
- stop pretending package names are proof of anything
Will that be annoying? Yes. Security is always annoying right up until the day it saves your ass.
What I want, really, is for developers to stop narrating this stuff like it’s natural weather. It isn’t. A package that spends its second life reading your SSH key and scribbling into your workflow is not “an ecosystem issue.” It is a break-in with better branding.
So here’s the sentence I wish every registry homepage would swallow like a cursed vitamin:
If it can run during install, it can hurt you during install.
A package that can rummage through ~/.ssh is not a helper. It’s casing the joint.