Between 01:24 UTC on 1 November 2026 and 02:33 UTC on 2 November 2026, two npm accounts —
cutekitten05 and bigdevin55 — published a cluster of packages built around one idea: take a
real, scoped SDK name and republish it without the scope. axelarjs-sdk
copies @axelar-network/axelarjs-sdk. wallet-adapter-base
copies @solana/wallet-adapter-base. sol-wallet-adapter
copies @project-serum/sol-wallet-adapter. contracts-upgradeable
copies @openzeppelin/contracts-upgradeable. GitHub's Advisory Database reviewed all four as
malware on 2 November, crediting the OpenSSF malicious-packages project (records MAL-2026-18456,
18459, 18452 and 18451).
The same accounts also published two packages under their own names —
cutekitten-test, whose README claims it is
"a security test package for a school project," and bigbob22-test,
with an empty README. Every one of the six ships the identical script.
One script, six names
Each advisory describes the same CWE-506 behaviour: the package "has no functional code." A
preinstall script runs node preinstall.js during npm install, and the script sends the
machine's hostname, OS username and local time to a Discord webhook the advisories label "PC
Notifier." None of the six does anything else — no real SDK, no stub exports, nothing to make a
build keep working. If a project actually tries to import axelarjs-sdk expecting the Axelar
client, it breaks immediately; the only "feature" that reliably works is the beacon firing on
install.
That's a smaller ambition than campaigns that ship a working no-op shim to avoid crashing the
build. This one doesn't bother. Whoever is behind it isn't trying to stay resident in a dependency
tree — they just want the install to happen once.
Checking the registry directly
The advisories give affected versions; the registry's own time and dist-tags fields show what
state each name is in right now:
$ curl -s https://registry.npmjs.org/wallet-adapter-base | python3 -c " import json, sys d = json.load(sys.stdin) print(d['time']) print(d['dist-tags']) " {'created': '2026-11-01T21:32:11.699Z', 'modified': '2026-11-01T21:33:07.093Z', '0.0.0-stage': '2026-11-01T21:32:11.699Z', '1.0.0': '2026-11-01T21:33:06.920Z'} {'latest': '1.0.0'} wallet-adapter-base went from a stub to its only real release, 1.0.0 — the version the advisory
names as malicious — in under a minute, and latest still points there. Running the same query
against sol-wallet-adapter and contracts-upgradeable shows the same thing: latest resolves to
1.0.7 and 1.0.0 respectively, both the versions the advisories flag. npm install today still pulls the beacon.
wallet-adapter-base
axelarjs-sdk is the exception. Its registry record now shows a single version, 0.0.0-stage,
with a created timestamp of 2026-11-02T02:30:26Z — after the account's original 1.0.1 release
the advisory describes. cutekitten-test and bigbob22-test show an unpublished block in their
time field instead of a current version at all. That's npm's usual pattern after a takedown: pull
the malicious release and leave an empty placeholder, or remove the name's history outright, rather
than simply flagging it. It also means "reviewed as malware" and "no longer installable" are two
different facts, and as of this writing only two of the six packages have both.
Where this fits on the pull request
Nothing here depends on a misspelling. axelarjs-sdk isn't a typo of @axelar-network/axelarjs-sdk
— it's the same name with the scope removed, which is exactly the string a developer might type
from memory, or that an AI assistant might generate if it drops the scope while filling in an
import. The same is true for wallet-adapter-base against @solana/wallet-adapter-base. Neither
requires the attacker to guess anything; the real package's own name is the bait.
On a pull request that adds one of these as a dependency, that's two independent signals a check
can act on without knowing anything about Discord webhooks: a package name a few hours or days old
with no history, and a preinstall script that runs code before anything else in the project does.
That's what MagAudit marks as critical on the lockfile line — whether it would have stopped the
merge depends on whether the team has made the check required in their own branch protection
settings. A general-purpose AI reviewer reading the diff has little reason to flag it: "wallet-adapter-base": "^1.0.0"
is syntactically ordinary, and nothing about the line itself resolves against the registry.
What this doesn't tell you
The advisories don't say who received the beacons, whether the Discord webhook had an audience
beyond its operator, or why a six-package campaign bothers squatting real SDK names at all when
the payload collects nothing more sensitive than a hostname and username — that's a long way from
the credential or session-token theft seen in other campaigns we've written about. We also don't
know whether cutekitten05 and bigdevin55 are the same person, or whether "security test package
for a school project" is a genuine excuse, a decoy, or an attempt to pre-empt exactly the kind of
writeup this is. We opened the four squat advisories and the two self-named ones directly; we
haven't independently confirmed the OpenSSF OSV records beyond what each GitHub advisory cites, and
we didn't attempt to resolve or contact the webhook endpoint.
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.
