On March 15, 2022, node-ipc maintainer Brandon Nozaki Miller (RIAEvangelist) published versions 10.1.1 and 10.1.2 of his package to npm. Buried inside was code that checked a user's public IP address against a geolocation lookup, and if the machine appeared to be in Russia or Belarus, it recursively overwrote every file on disk with a heart emoji (❤️). node-ipc was pulling roughly 1.1 million weekly downloads at the time and was a transitive dependency of vue-cli, meaning the payload rode into an untold number of downstream builds without any of those developers touching node-ipc directly. The incident was assigned CVE-2022-23812 with a CVSS score of 9.8, and it became the case study that put the word "protestware" into every security team's vocabulary. Here is what actually happened, how it spread, and how to stop the next one before it ships.
What is node-ipc, and why did a single maintainer's decision matter so much?
node-ipc is a Node.js module for local and remote inter-process communication, and it mattered because it sat quietly inside vue-cli, one of the most-used scaffolding tools in the JavaScript ecosystem. Miller had maintained the package since 2015, and by 2022 it had accumulated dependents that had no idea it existed in their tree. vue-cli depended on node-ipc through the @vue/cli install chain, which meant any team running vue create or updating a Vue project could pull the compromised release without ever adding node-ipc to their own package.json. This is the structural risk of transitive dependencies: the security posture of your build is defined by packages you never explicitly chose, maintained by people you've never vetted, three or four levels deep in your lockfile.
What did the malicious code in node-ipc actually do?
The code checked the machine's IP-derived country code and, for Russia or Belarus, executed a destructive file-overwrite routine instead of the message-only behavior it showed elsewhere. Miller shipped the payload through a new dependency he created called peacenotwar, first published on March 7, 2022, then wired it into node-ipc itself on March 8 via versions 9.2.2 and, more destructively, into 10.1.1/10.1.2 on March 15. The geolocation check used the node-geo-location package to query an IP API; on a match, a function named onFire() walked the filesystem and replaced file contents with a heart emoji, and a second function attempted to write a "WITH-LOVE-FROM-AMERICA.txt" file to the desktop. Outside the targeted geographies, the same versions only printed a peace message to the console — but the destructive branch was live code sitting in a package with a million weekly pulls, not a hypothetical.
How did npm's versioning model let a maintainer push this to existing installs?
It happened because node-ipc's dependents used caret (^) version ranges, which let npm silently pull 10.1.1 and 10.1.2 into builds that had previously pinned an earlier "safe" version. Projects that specified "node-ipc": "^9.2.1" or similar ranges were eligible to resolve to the compromised releases on the next npm install, with no code change on the consuming project's side. GitHub's security advisory for the issue, GHSA-4wf5-vphf-c2xc, and the corresponding CVE-2022-23812 both note the vulnerable range spanning versions 9.2.2 and 10.1.1–10.1.2. npm deprecated the affected versions within days, and Miller subsequently pushed further changes that removed the destructive logic but kept the protest messaging — yet by then the packages had already been live on the registry for roughly a week, plenty of time for CI pipelines running unpinned installs to fetch them.
Was node-ipc an isolated incident, or part of a broader pattern?
It was part of a broader pattern that researchers quickly labeled "protestware," and node-ipc was joined within days by a similar case in the es5-ext package. Snyk researchers documented that es5-ext, with around 700,000 weekly downloads at the time, shipped a postinstall script that detected Russian and Belarusian IP addresses and displayed an anti-war message in the terminal — non-destructive, but installed without consent through the same dependency-tree mechanics. The common thread in both cases: a maintainer's personal, politically-motivated code change reached production systems through ordinary npm install runs, with no exploit, no CVE-worthy bug in the traditional sense, and no malicious actor outside the trusted maintainer. Security teams that had spent years building processes around external attackers had comparatively little tooling for a trusted insider deciding to weaponize their own package.
What should security teams actually take away from node-ipc three years later?
The takeaway is that pinned, reviewed dependency versions and CI-time integrity checks catch this class of issue faster than reactive incident response. Teams that had locked node-ipc to an exact version with a checksum-verified lockfile (package-lock.json with npm ci rather than npm install) were not exposed to the auto-pulled 10.1.1/10.1.2 releases. Teams running software composition analysis with behavioral or diff-based scanning — flagging a dependency update that suddenly adds filesystem-write and network-geolocation calls it didn't have the week before — could have caught the change before it reached a build server, rather than after a postmortem. The incident is also why OpenSSF and several registries subsequently pushed for more transparent maintainer-change and package-diff visibility on npm, since the original vulnerability report noted the malicious behavior wasn't hidden through obfuscation — it was sitting in plain, readable JavaScript that nobody diffed before upgrading.
How Safeguard Helps
Safeguard is built for exactly this failure mode: a trusted, widely-used package changing behavior between versions in a way that reachability analysis, not just a CVE feed, would flag. Our reachability engine traces whether a package like node-ipc is actually invoked by your application's code paths, so teams can prioritize the dependencies that matter instead of chasing every advisory across a lockfile. Griffin AI reviews dependency diffs and pull requests for suspicious new behavior — filesystem writes, network calls to geolocation or IP-lookup services, and postinstall scripts — surfacing exactly the kind of change that made node-ipc's 10.1.1 release dangerous. Safeguard generates and ingests SBOMs so you can answer "are we exposed" the moment a CVE like CVE-2022-23812 drops, and our auto-fix PRs pin or roll back affected packages to a known-safe version automatically, closing the window between disclosure and remediation.