On the morning of 19 October 2026, GitHub's Advisory Database reviewed two npm packages as malware: items-validator and item-validator — names one letter apart, in the same batch of advisories. Looked at side by side on the registry, they turn out to be two different supply-chain patterns wearing the same name.
What the advisories actually say
Both are short, and both say the same thing in the same words: "Any computer that has this package installed or running should be considered fully compromised," with a recommendation to rotate every secret on the affected machine from a different computer and remove the package, while warning that removal alone may not clean up whatever it already did. Both are classified CWE-506, "Embedded Malicious Code." Neither advisory describes the actual payload, names a CVE, or links to the code — this is the standard malware-advisory boilerplate GitHub publishes when a package is pulled, not a writeup of what it does. We're not going to guess at the mechanism from two sentences; what follows is what we could check ourselves, directly against the registry.
One package is three weeks old. The other is six years dormant.
The registry's own time field — the publish timestamp of every version a package has ever had — is public and doesn't get rewritten when npm pulls a package for malware, even though the actual version contents do:
$ curl -s https://registry.npmjs.org/items-validator | python3 -c "import json,sys; print(json.load(sys.stdin)['time'])"
{'1.0.4': '2026-09-28T08:37:45.576Z', '1.0.5': '2026-09-28T12:00:19.110Z',
'0.0.0-stage': '2026-10-19T06:24:58.173Z', '0.0.1-security': '2026-10-19T06:25:55.248Z'}
items-validator had exactly two real versions, both published 28 September — three weeks before the advisory. That's the textbook shape of a newly-published, low-adoption dependency: a handful of versions, no track record, added to someone's package.json while it was still fresh.
item-validator (singular) tells a completely different story:
$ curl -s https://registry.npmjs.org/item-validator | python3 -c "import json,sys; d=json.load(sys.stdin)['time']; print(min(d.values()), max(v for k,v in d.items() if not k.startswith('0.0')))"
2019-12-30T14:30:58.588Z 2020-02-20T21:05:26.313Z
That package shipped more than 70 versions between December 2019 and February 2020, then nothing — no release, no advisory, no activity of any kind — for over six years. Then, this morning, it was quarantined for the same reason as its three-week-old near-namesake. Both registry entries now show "maintainers": [{"name": "npm", "email": "npm@npmjs.com"}] and "description": "security holding package" — npm's standard placeholder once it pulls a package for malware and takes over the name itself.
A package dormant for six years and then suddenly shipping new versions is a different failure mode from a brand-new package with no history: it usually means an attacker got control of an abandoned maintainer account or an expired registration, not that someone registered a fresh typosquat. Age alone doesn't distinguish them — item-validator is, by every age-based signal, an old and presumably trustworthy dependency, right up until it isn't.
The download numbers, for what they're worth
npm's public stats endpoint still has a record for both, from before either was pulled:
$ curl -s https://api.npmjs.org/downloads/point/last-month/items-validator
{"downloads":736,"start":"2026-09-17","end":"2026-10-16","package":"items-validator"}
$ curl -s https://api.npmjs.org/downloads/point/last-month/item-validator
{"downloads":0,"start":"2026-09-17","end":"2026-10-16","package":"item-validator"}
736 downloads in under three weeks is not nothing for a package with two versions and no public repository we could find. It could mean genuine early adoption; it could mean automated download activity, which is a known way to make a young package look more established than it is. The endpoint doesn't distinguish the two, and we're not going to pick one explanation and present it as fact. item-validator's zero fits a package nobody had reason to install in the month before its old name got reused.
Where this fits on the pull request
items-validator is exactly what a dependency-age and adoption check is built to catch: new, thin version history, added to a lockfile for the first time. On a pull request that introduces it, that's what MagAudit marks as critical, with the file and line of the lockfile change — whether that stops the merge depends on whether the team has made the check required in their own branch protection settings. item-validator is the harder case for any check built around novelty: a six-year-old name with a real publish history doesn't look new to an age heuristic on the day it's added, because in every dependency tree that already pinned it months ago, it wasn't added this week at all — the risk only appears retroactively, when a dormant name starts shipping again.
What this doesn't tell you
Neither advisory says what the payload actually did, so we haven't described one. We don't know whether item-validator's takeover was a compromised maintainer account, an expired email domain, or something else — GitHub's advisory doesn't say, and nothing in the registry metadata confirms it either way. We don't know if the 736 downloads of items-validator represent real installs by real developers or inflated numbers from the campaign itself; the stats endpoint can't tell the two apart, and we haven't found a second source that can. And we don't know whether the two packages share an operator — same naming pattern, same advisory batch, same morning, but that's circumstantial, not confirmed.
MagSolutionsAI