DEV Community

OtterCyborg
OtterCyborg

Posted on • Edited on

I Got Hit by Sha1-Hulud: How I Rebuilt My Development Environment from the Ashes

I Got Hit by Sha1-Hulud: How I Rebuilt My Development Environment from the Ashes

Yesterday, my MacBook started running hot. Not the usual "Chrome has 47 tabs open" kind of hot—the "something is very wrong" kind of hot. I opened Activity Monitor and saw a process called trufflehog consuming 700% CPU.
That's when I knew: I was compromised.

The Attack

It started innocently enough. I installed Postman CLI to test some APIs—a completely normal thing developers do every day. What I didn't know was that one of the npm packages in my dependency chain had been poisoned. The malware created a tunnel, exfiltrated my SSH keys, and was actively scanning my machine for secrets.
I had become another victim of Sha1-Hulud.

The Aftermath

I had to revoke everything. Every SSH key. Every API token. Every secret. Then I nuked my Mac entirely and reinstalled the OS fresh.
All of this happened in a single day. Standing in front of a blank machine yesterday evening, I had a choice: set everything up the same way I always had, or fundamentally rethink my approach to development environment security.
I chose the latter. Here's the setup I built in just a few hours.

First Principle: No Node.js on the Host

Here's the uncomfortable truth: running npm install on your host machine is playing Russian roulette. Any package in your dependency tree—or any of their dependencies—could execute arbitrary code during installation via lifecycle scripts like preinstall and postinstall.
My first rule for the new setup: No Node.js. No npm. No Bun. Nothing JavaScript on my host environment.
This might sound extreme, but consider what you're actually trusting when you run npm install:

  • The package author
  • Every maintainer of every transitive dependency
  • npm's infrastructure
  • Every developer account that has publish access to any of those packages
  • The security of every one of their machines and credentials

⠀That's an impossibly large attack surface.

Second Principle: Declarative, Not Imperative

I also removed Homebrew. Before you close this tab in disgust, hear me out.
Homebrew is fantastic for quickly installing tools. But it creates a sprawling web of dependencies in /usr/local that's nearly impossible to audit. After months of use, you have no idea what's actually installed or why.
Instead, I switched to Nix with a declarative configuration. Everything I need is defined in a single file:

home.packages = with pkgs; [
    # Container
    container # Apple Container

    # Rust development
    rustc
    cargo
    rustfmt
    rust-analyzer
    clippy

    # Python development
    python312
    python312Packages.pip
    python312Packages.virtualenv

    # Common development tools
    git
    bat

    # Editor
    neovim
  ];
Enter fullscreen mode Exit fullscreen mode

That's it. My entire host environment is defined in roughly 20 lines. If I need to nuke and rebuild my machine again, I can be back to a working environment in minutes, not hours.
Here's what my /usr/local/bin looks like now:

ls /usr/local/bin
determinate-nixd
Enter fullscreen mode Exit fullscreen mode

One binary (because I installed nix using determinate installer). Compare that to the hundreds of executables Homebrew scatters across your system.
Nix gives me several security advantages:

  • Reproducibility: My environment is identical every time I build it
  • Isolation: Packages are stored in /nix/store with unique hashes based on their entire dependency tree
  • Auditability: I can see exactly what's installed by reading one file
  • Easy rollback: Made a mistake? Roll back to any previous generation

Third Principle: Protect Your SSH Keys

Here's something I didn't fully appreciate before the attack: any program on your machine can read your SSH keys. There's no permission prompt, no confirmation dialog. If malware lands on your system, your keys are immediately compromised.
I now use Secretive, an open-source macOS app that stores SSH keys in the Secure Enclave—the same hardware security module that protects Face ID data. The private key literally cannot be exported; it never exists in accessible memory.
Even better, it requires biometric authentication for every operation. Every git push, every ssh connection requires a Touch ID confirmation. It adds a bit of friction, but that friction is the point. If malware tries to use my keys, I'll know immediately—and I can deny it.
The Secure Enclave approach means even if an attacker gets root access to my machine, they still can't extract my SSH keys. The hardware won't allow it.

Fourth Principle: Contain the Danger

I still need to work with Node.js projects. The JavaScript ecosystem isn't going anywhere, and many of the tools I use daily are built on it. The solution: containerization.
Apple recently released their own containerization framework, and it's philosophically different from Docker. Instead of running all containers in a single shared Linux VM, Apple's approach spins up a dedicated lightweight VM for each container. This provides hypervisor-level isolation—each container is as isolated as a full virtual machine, but with sub-second startup times.
For my work, I use a hybrid setup:

  • Web applications run entirely inside containers (npm is trapped there forever)
  • For Tauri apps, the web portion is containerized and served over the network
  • The native shell runs on my host, connecting to the containerized web server

This setup means JavaScript code never runs on my host machine. Even if a malicious npm package executes, it's sandboxed inside a container with no access to my SSH keys, no access to my credentials, nothing.

The New Workflow

Here's what development looks like now:

  1. Clone a repo: Git prompts for Touch ID to use my Secure Enclave-protected key
  2. Start the dev environment: Apple Container spins up an isolated Linux VM in under a second
  3. Install dependencies: npm install runs inside the container, isolated from everything
  4. Push changes: Another Touch ID confirmation

Is it more friction? Yes, marginally. Is it more secure? Absolutely.

Lessons Learned

The Sha1-Hulud attack taught me something uncomfortable: the convenience-first approach to development tooling is a liability. We've built an ecosystem where running a single command can execute arbitrary code from thousands of strangers.
Some might argue this is paranoid. To them, I'd point out that supply chain attacks are increasing in sophistication and frequency. The npm ecosystem specifically has been hit repeatedly—Sha1-Hulud is just the latest and most severe example.
Here's my advice for anyone who wants to take security more seriously:

  1. Assume npm packages can and will be compromised. Treat npm install as a potentially hostile operation.
  2. Run JavaScript in containers. It's the only way to meaningfully limit the blast radius.
  3. Protect your SSH keys with hardware. Secretive (or a YubiKey) makes key theft orders of magnitude harder.
  4. Make your environment declarative and reproducible. You should be able to rebuild from scratch quickly, because someday you might have to.
  5. Accept the friction. Security that's easily bypassed isn't security.

I spent a few hours setting all this up yesterday. The next person hit by a supply chain attack will spend days—or weeks—on incident response and recovery. The math works out.

Looking Forward

Eventually, I want to get even more aggressive. Running Python directly on my host still makes me nervous; pip packages have their own security issues. The ideal end state might be a completely containerized development environment where only Nix-managed tools run on the host.
But for now, this setup represents a reasonable balance. I can still be productive while significantly reducing my attack surface.
The sandworm got me once. It won't get me again.

If you were affected by Sha1-Hulud, the key remediation steps are: revoke and regenerate all npm tokens, GitHub PATs, SSH keys, and cloud credentials. Search for repositories named "Sha1-Hulud" created under your accounts. Review for unauthorized workflows or suspicious commits. And consider whether your development environment security model is actually working for you.

Top comments (0)