Forks of Baileys , the popular WhatsApp Web library, silently make the installer’s WhatsApp account follow channels the package author controls. Some forks also inject the author’s advertising URL into media the bot sends. One fork sends a message from the installer’s account and then blocks the bot. This is non-consensual social abuse shipped through npm. It is not credential theft.
Continuous monitoring of the npm registry records 4,250 package names that contain baileys and another 112 that contain libsignal-node . The set includes the upstream library, legitimate forks, mirrors, and many packages no one has examined. This post lists only the packages confirmed as malicious in this campaign: 82 package names built on Baileys across 375 versions, and 15 libsignal-node impersonators across 38 versions. Everything outside that confirmed set remains unverified, not cleared as safe. The confirmed count is a lower bound, and the campaign keeps growing.
A silent, non-consensual follow of attacker-owned WhatsApp channels, using the installer’s account
A remotely controlled follow list, with each channel muted to hide the subscription ( lupy4u )
The author’s advertising URL injected into every image and video the bot sends ( mamz-baileys )
Forged channel attribution added to the installer’s outgoing messages ( @cikikomo/baileys )
A message sent from the installer’s account, then an error that blocks the bot ( @prototypevip/baileys )
Indicators of Compromise (IoC):
npm publishers: prototype1006 , cikikomo , neykoor , mamzhandsome , lupy4u , diezyyasha
Maintainer emails: [email protected] , [email protected] , [email protected] , [email protected] , [email protected] , [email protected]
Advertising URL injected into media: hxxps://fiora[.]nixel[.]my[.]id/ ( mamz-baileys )
Remote follow-list source: hxxps://raw[.]githubusercontent[.]com/LevviCodeID/Levi4than/refs/heads/main/levvleys.json ( lupy4u )
channel identifiers: 120363401404146384@ ( @neykoor ), 120363426628484388@ ( @cikikomo ), 120363406881628130@ ( mamz-baileys , shared with diezyyasha-baileys )
lupy4u control repository: GitHub LevviCodeID/Levi4than ( lupy4u pulls its follow list from levvleys.json there); operator site levvicode[.]cloud
Part 1: The campaign and impacted packages
Why Baileys is a target
Baileys is a WhatsApp Web multi-device library for Node.js. Developers use it to build WhatsApp bots.
These forks target the authenticated session. A paired session can send messages, follow channels, and read chats as the account holder. An attacker who controls the session controls the account.
These packages are the examples analysed here. Source review covers all but one. npm removed @diezyyasha/libsignal-node before analysis, so that row reflects public reports only.
A package appears here only after a confirmed malicious verdict. The first list covers packages built on Baileys. The second covers libsignal-node impersonators, including the import-time patcher.
What links the packages
Each package is a different npm account with a different email. Most follow different channels. The verified evidence does not show that one operator controls all of them. The packages overlap in one place. mamz-baileys follows 120363406881628130@ . A record for the removed diezyyasha-baileys lists the same channel. Apart from this overlap, the packages only the forced-follow technique. The evidence points to independent operators that reuse the same technique.
The forced follow appears in three forms across the packages, from a fixed target to a remotely controlled list.
Fixed target. @neykoor/baileys follows one hardcoded channel on every connection open.
Covert attribution. mamz-baileys follows a fixed channel and also injects an obfuscated advertising URL into every media message.
Remote control and concealment. lupy4u fetches its target list from a public GitHub file, follows each channel, and then mutes it. The operator changes targets without republishing, and the mute hides the subscription from the account owner.
@prototypevip/baileys is different. It abuses the same authenticated session, but to send a message from the installer and block the bot.
Part 2: technical analysis
All confirmed packages act through the installer’s authenticated session. They do not steal a static secret such as a token. The differences are which action they take and how the code reaches the session.
@neykoor/ [email protected] follows a hardcoded channel on every connection. The implant sits in lib/Socket/ .js .
Three properties make it deliberate. It binds to an automatic lifecycle event that no bot developer calls, discards the response with a fire-and-forget query, and hides every error with an empty catch. The pre-check keeps it silent on later reconnects. The socket chain shows the code reaches the listener at runtime. makeWASocket builds down through messages-send.js , which calls makeNewsletterSocket , which registers this listener.
[email protected] moves the target list off the package and onto the network. autoJoinChannels() in lib/Socket/ .js fetches a JSON file from GitHub, then follows and mutes each channel it returns.
The list is remote, so the operator changes the targets without publishing a new version. The code pairs each follow with a mute, which stops the notification that would show the account owner the new subscription. It offers no opt-out and no consent prompt.
An advertising URL injected into media
[email protected] adds a second behaviour on top of a forced follow. In lib/Socket/messages-send.js , at two sites, it sets a sourceUrl on the preview payload of every image and video the bot sends. It builds the URL from a character-code array rather than writing it as text.
Every other URL in the file is a plain string. Only this one comes from character codes. The two forms behave the same at runtime, so the character codes serve only to keep the URL out of a text . The author’s domain then rides on the media the installer sends to their own contacts.
Forged attribution on outgoing messages
@cikikomo/ [email protected] adds the operator’s channel attribution to the victim’s outgoing messages from lib/Socket/luxu.js .
The same revision adds noSelfSync: true at four message-send sites. That flag suppresses syncing the sent message back to the victim’s own devices, which lowers the chance the account holder notices the injected attribution. The package advertises both the channel identifier and the noSelfSync flag in its own package.json description, so the concealment targets the victim, not the buyer of the fork.
Account block through an authorisation gate
@prototypevip/ [email protected] hides an authorisation gate in lib/Store/prototype-store.js . The file opens with a base64 string table and a one-line decoder.
The gate walks each message object, finds the live multi-device socket, and compares its key to the author’s own key gintoki . If the keys do not match, it sends an unauthorised-use notice from the victim’s account and throws to halt message handling.
cloneM() wraps the gate and runs inside the messages.upsert listener, so it runs on every message the bot receives, not only at startup. A legitimate licence check has no reason to hide the word sendMessage behind base64. The author hid it on purpose.
The Latest from SafeDep blogs
Follow for the latest updates and insights on open source security & engineering
I checked every action of my own Claude Code agent against a profile of how I work and a set of org policies, using Jev. It caught 14 of 14 attacks for $0.15 per 1,000 events.
An attacker used a Go worm to steal CI publish tokens from MemTensor and ship malicious MemOS packages to npm and PyPI. See how it works, with code and indicators of compromise.
The May 2026 Mini Shai-Hulud worm is still infecting new GitHub repositories. Hijacked actions-cool/issues-helper tags planted Claude Code and VS Code hooks in six popular repositories between 20 and...
sckit is a Go implant framework that steals developer and CI credentials and carries templates to spread through npm, PyPI, and GitHub Actions. Static analysis and indicators of compromise.
Start free with open source tools on your machine. Scale to a unified platform for your organization.
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
