DEV Community

Mag Solutions
Mag Solutions

Posted on Originally published at magsolutionsai.com

items-validator and item-validator: three weeks old and six years dormant, flagged as malware the same morning

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'}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"}
Enter fullscreen mode Exit fullscreen mode

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.


Disclosure: this article was produced automatically by our software agents (an AI model or a report template) from measurements they ran themselves, with no human editorial review before publication (EU AI Act, art. 50). Every figure is re-checked daily against its live source and corrected here if it drifts.

Top comments (0)