On March 7, 2022, node-ipc versions 10.1.1 and 10.1.2 shipped with code that checked a user's IP geolocation and, if it resolved to Russia or Belarus, overwrote files on disk with a heart emoji. The maintainer, Brandon Nozaki Miller (RIAEvangelist), added the payload directly to a package with roughly a million weekly downloads that shipped transitively through Vue CLI and unpkg, meaning developers who had never heard of node-ipc pulled it in anyway. Two later versions, 11.0.0 and 11.1.0, added a dependency called "peacenotwar" that dropped a file named WITH-LOVE-FROM-AMERICA.txt onto the user's desktop and every subdirectory it could reach. GitHub assigned the incident CVE-2022-23812 and npm pulled the affected releases, but the fix — version 10.1.3 — only patches this one payload. It does nothing about the underlying trust model: every npm install grants a maintainer's code the same execution rights as your own, and no scanner that only checks known-CVE databases would have caught this before it shipped, because there was no CVE yet. Four years on, the incident is still the clearest public case study of what a checklist for maintainer-inserted risk needs to cover.
What actually happened in the node-ipc incident?
The payload lived directly in the package's own source, not in a compromised dependency or a hijacked npm account, which is what makes it different from a typical supply chain attack. RIAEvangelist added a file that geolocated the installing machine's public IP and, when the country resolved to Russia or Belarus, recursively overwrote files with a heart emoji — a destructive, non-consensual action with no opt-out. Versions 10.1.1 and 10.1.2 (published within roughly a day of each other) carried this logic; the maintainer then published 11.0.0 and 11.1.0 with a separate "peacenotwar" module as a dependency, which was comparatively benign — it wrote a protest text file rather than destroying data. Both npm and GitHub Advisory Database logged the issue as CVE-2022-23812, and downstream projects like Vue CLI and Unity's dependency chains had to scramble to pin safe versions, since many consumers had loose semver ranges like ^10.1.0 that auto-upgraded into the malicious release.
Why did a semver range make this worse?
Because node-ipc's own package.json and the countless downstream package.json files depending on it used caret ranges (^10.1.0), npm's default resolution behavior pulled the malicious 10.1.1 and 10.1.2 releases into existing projects automatically on the next install or CI run — no action by the downstream developer was required. This is the same mechanism that makes semver useful for routine bug fixes and dangerous for a maintainer acting in bad faith: nothing in the npm registry distinguishes "patch that fixes a null pointer" from "patch that destroys the user's filesystem." Lock files (package-lock.json, yarn.lock) would have prevented an unplanned upgrade for projects that already had one committed and respected in CI, but many CI pipelines of that era ran a fresh npm install without --frozen-lockfile or ci, silently accepting the new version. The incident is a concrete argument for treating lockfile drift itself as a signal worth alerting on, not just a convenience.
How is a maintainer-inserted logic bomb different from a compromised account?
A compromised-account attack (like the 2021 ua-parser-js or 2018 event-stream incidents) involves an attacker who is not the legitimate maintainer gaining publish rights and slipping malware into an unrelated release; the real maintainer typically didn't know until users reported it. In node-ipc, the person who shipped the destructive code was the verified, long-standing maintainer acting deliberately, using their own signed npm credentials with no anomaly in login pattern or publishing cadence. That distinction matters for detection: account-takeover heuristics — new device, unusual publish time, geographically anomalous login — are useless here because nothing about the publishing event itself was abnormal. What was abnormal was the code's runtime behavior: new filesystem-write logic and new network calls (to resolve geolocation) that did not exist in any prior version of the package. Detecting this class of incident requires diffing behavior release-over-release, not just checking who published it.
What would have caught this before install?
Behavioral diffing between package versions is the single most direct answer: node-ipc 10.1.1 introduced file-write and IP-geolocation logic that had no equivalent in 10.0.x, and any tool that diffs the actual runtime behavior of a new release against its predecessor — rather than just its declared permissions — would have flagged it as a new capability appearing in a patch-level version bump, which is itself unusual. A second, complementary signal is dependency-graph anomaly: the "peacenotwar" package was brand new, had no independent reputation, and was added as a mandatory (not optional) dependency of a package with no prior indication it needed one. Security researcher Liran Tal at Snyk and the broader npm security community pointed out at the time that pinning exact versions and auditing new transitive dependencies before they land would have contained the blast radius even without predicting the specific payload.
What should a maintainer-risk checklist actually include?
A practical checklist, derived directly from this incident, has five parts: (1) diff runtime behavior — not just source diffs, but actual filesystem, network, and process activity — between a new release and its immediate predecessor, and treat new capabilities appearing in a patch version as a hard flag; (2) treat every new transitive dependency added to an existing package as an event worth reviewing, especially when it's freshly published and has no independent install base; (3) pin exact versions or maintain lockfiles that are actually enforced in CI (npm ci, not npm install); (4) track publisher behavior over time, since a maintainer whose code has been stable for years shipping abrupt, destructive, geography-conditional logic is itself an anomaly regardless of account status; and (5) assume no CVE will exist at the moment of first exposure — CVE-2022-23812 was assigned after the fact, so detection has to work on behavior, not database lookups.
How Safeguard Helps
Safeguard's Eagle classification model scores every npm publish — including retroactive scans going back a decade — against seven indicator classes, one of which is explicitly "behavior divergence from prior versions": new network, filesystem, or process activity that didn't exist in the package's previous release is exactly the signal that would have caught node-ipc 10.1.1 the moment it hit the registry, independent of whether the change came from a compromised account or a legitimate maintainer acting alone. Eagle also flags the "trust warm-up" pattern — a handful of benign releases before a malicious one — as a bypass-attempt indicator in its own right. When Eagle's model is updated, it re-scores the full historical corpus, so if a package your build already depends on gets reclassified, you get a finding within seconds rather than waiting for a CVE to be filed. The Gold Registry blocks any artifact Eagle scores above its malicious threshold before it ever reaches your install step, closing the gap that a caret-range semver upgrade opened in March 2022.