Keeping Shai-Hulud off the Mélange | Aymeric on Software
Unless you’ve been keeping your head in the sand, you may have heard of Shai-Hulud. I’m not talking about the giant worm from Frank Herbert’s Dune novel, but the self-replicating supply-chain worm that has targeted the npm registry multiple times. The mélange here does not refer to Dune’s spice, the mythical substance that grants prescience or extends your lifespan. Instead, drawing on the word’s French etymological roots, I use it to refer to the strange mixture of projects and personal documents that we developers typically have on our workstations.
As developers, we have the tendency to keep powerful authentication tokens and SSH keys on our machines. They sit side by side in project directories, ready to be harvested. Meanwhile, we fearlessly execute code freshly downloaded from the internet (via npm or any package registry). When that code breaks containment, it can compromise not only a given project’s code and its secrets, but also every other file and anything else of value that may lie on our computers.
Worse still, we are now increasingly giving the keys to our kingdoms to autonomous AI coding agents, with sometimes catastrophic consequences. Such agents may be subject to prompt injection, or they may be so eager to accomplish their task that they will happily break containment, in a way that is reminiscent of the paperclip maximizer parable, popularized by Nick Bostrom.
Contents
TL;DR: How I protect myself from Shai-Hulud
Dev Environment Isolation
Supply-Chain Attack Protection
SSH Key Hygiene
Secrets Management
Conclusion
TL;DR: How I protect myself from Shai-Hulud
Shai-Hulud was a call to action. Consequently, I have been rethinking my working practices and sharpening my tools to reduce the blast radius of such compromises, since it is a given that supply-chain attacks are here to stay.
Having a computer dedicated solely to development is currently off the cards due to the increased cost of hardware caused by the AI bubble and RAMageddon in particular. I have also been very curious about Linux on the desktop (Omarchy), and I am on the fence about upgrading my hardware at this time.
What follows is what I have decided to do, using my current hardware (a Mac Studio M1) and my current usage patterns. These solutions may not fully work for you, and in fact, they do not fully work for me either.
One thing I should get out of the way is that I do not use GitHub Actions to build anything, let alone deploy to production. I use my own “compute” for builds, and I do not give production secrets to online third parties like GitHub or any fancy OIDC trusted compute providers.
Dev Environment Isolation
All builds occur in dev containers instead of running loose directly on my computer.
Developer tools (VS Code, Cursor, Zed, etc.) are easily configurable to run the dev environment in a container via extensions.
When dev containers cannot be used (e.g., Electron apps), I use VMs and connect the editor via SSH. This is a bit heavier than the above, but the experience remains comparable.
For simple cases, I use Microsoft Dev Container images for VS Code (e.g., just Node.js/npm).
For more complex cases or for VMs, I tend to use mise or devenv. These tools typically let you pin exact tool versions in lock files to get reproducible builds.
AI agents also run in dev containers (in my case, mostly Cursor, Codex, and Claude).
I use OrbStack on macOS instead of the official Docker Desktop, as it offers better performance. The free tier is sufficient for my needs.
Prevent Supply-Chain Attacks
Extension auto-updates are disabled in the base VS Code IDE (or forks like Cursor), but I update them regularly.
I force all the extensions that can run in the context of the dev container to run there.
I configure package managers like npm to:
Not install recent packages (say, less than 7 days old).
Not run install scripts automatically without opt-in (that’s actually the default now).
I use the free tier of the Socket Firewall (sfw) to scan packages when possible (e.g., it won’t work for NuGet/C# packages without paying lots of dinero).
I alias the npm, npx, cargo, etc. commands to sfw, so I don’t have to remember to use sfw when I type commands.
Access Token Hygiene
All access tokens (AWS, Cloudflare, etc.) are IP-restricted and project-specific.
Access tokens are configured to use the minimum set of permissions needed per project.
No god-mode tokens in the global ~/.aws directory or local .env files. No exceptions.
All tokens are always encrypted and persisted on disk using age.
Decryption requires user interaction (Touch ID), and the decryption key is held in hardware (TPM, Secure Enclave) via age-plugin-se.
SSH Keys
For access to servers, I now use Secretive, which leverages the Secure Enclave and requires interaction with Touch ID.
For GitHub, I use normal SSH keys with strong passwords stored in macOS Keychain.
For GitHub...