Eighty-three versions. Two npm accounts. Six packages. All of them impersonate the Baileys WhatsApp Web library, and all of them were published across a 105-day window from 5 March 2026 to 18 June 2026. The campaign ends with @sauruslord/libsignal, a package that impersonates Open Whisper Systems’ Signal protocol library and uses it as a trojan horse to overwrite a file inside your legitimate @whiskeysockets/baileys installation on disk, wiring your authenticated WhatsApp session to an attacker-controlled newsletter channel without any user action.
Campaign Cluster Map
| Wave | Package(s) | First Published | Payload Class | Publisher Account |
|---|---|---|---|---|
| 1 | @sauruslord/baileys, sauruslord-baileys | 2026-03-05 | Class 1 (credential / session stealer) | sauruslord |
| 2 | sauruslord-baileys (2.x, 3.x), zaldy-baileys, @sauruslord/libsignal | 2026-03-23 | Class 1 + filesystem implant | sauruslord, zaldy |
| 3 | @fhkry/baileys-v2, @fhkry/x-baileys | 2026-04-02 | Class 1 | fhkry |
All six packages have been security-held by npm as of 15 July 2026 and are confirmed malicious under MAL-2026-10657, MAL-2026-10659, MAL-2026-10661, MAL-2026-10663, MAL-2026-10664, and MAL-2026-10665.
Wave 1: The @sauruslord Namespace Opens (5 March 2026)
Package Anatomy
The sauruslord account registered the @sauruslord npm scope and published @sauruslord/baileys at 15:18 UTC on 5 March 2026. Seventeen minutes later, sauruslord-baileys appeared as an unscoped variant under the same account. Both impersonate @whiskeysockets/baileys, the leading open-source WhatsApp Web library maintained by WhiskeySockets with over 50 published versions since May 2023.
The cross-reference we ran against the npm registry time field for sauruslord-baileys shows 13 versions published on launch day alone, from 1.0.2 at 15:40 UTC through 1.1.3 at 23:32 UTC. The operator continued iterating through 5 March and into the early hours of 7 March, then paused for six days before resuming on 13 March. By the time the 1.x series ended, sauruslord-baileys had accumulated 19 versions across three days of active publishing.
Version Timeline: Wave 1
| Package | Version | Published (UTC) | Notes |
|---|---|---|---|
@sauruslord/baileys | 1.0.0 | 2026-03-05 15:18 | @sauruslord scope created; scoped variant |
@sauruslord/baileys | 1.0.1 | 2026-03-05 15:27 | Patch 9 minutes after initial publish |
sauruslord-baileys | 1.0.2 | 2026-03-05 15:40 | Unscoped variant launched 22 minutes later |
sauruslord-baileys | 1.0.3 through 1.1.3 | 2026-03-05 17:23 to 23:32 | 9 versions in 7 hours: rapid payload iteration |
sauruslord-baileys | 1.1.4 through 1.1.8 | 2026-03-06 to 2026-03-07 02:38 | Day 2 iteration continues into early morning |
sauruslord-baileys | 1.1.9 | 2026-03-13 17:40 | 6-day gap; activity resumes |
sauruslord-baileys | 2.0.0 | 2026-03-15 05:35 | Major version bump; 2.x series begins |
Eleven versions published in the first eight hours is not normal package maintenance. It is a payload tuning cycle.
Execution Trigger
The sauruslord-baileys package carries a preinstall lifecycle hook that executes engine-requirements.js before npm writes any package files to disk. The evidence file recovered from versions 3.0.0 through 3.0.2 and confirmed by Amazon Inspector (SHA-256: 9b0ac7033c5a7f5646f4bdbe08fe542a2d26031fd5f4ca1f082f6972ee383a45) shows the filename engine-requirements.js as the preinstall payload carrier. A file named lib/index.js (SHA-256: 69a6ca2dcaf905a690fbf65030aa486217975358a54077c7b05bce9cf2bfa1da) contains the primary module-level execution logic.
The scripts block from the registry metadata reads:
{
"preinstall": "node ./engine-requirements.js"
}preinstall fires before the install phase, meaning the payload runs on the machine performing npm install regardless of --ignore-scripts at the dependency layer. Any project that lists sauruslord-baileys as a direct or transitive dependency executed this code.
Wave 2: Satellite Accounts and the libsignal Implant (23 March 2026)
Wave 2 is where the campaign scope expands and the most technically significant package appears.
zaldy-baileys: Same Session, New Account
On 23 March 2026, a new npm account named zaldy published zaldy-baileys at 11:03 UTC. The sauruslord account published sauruslord-baileys 2.0.1 at 11:45 UTC that same morning, 42 minutes later. Two accounts, one publishing session. The shared timing brackets a single operator coordinating multiple npm identities to expand coverage of the Baileys namespace across a broader set of user search queries.
zaldy-baileys carries a single version (2.0.0) and is confirmed malicious under MAL-2026-10663.
@sauruslord/libsignal: The Filesystem Implant
Three days after the zaldy/sauruslord coordinated publish, on 26 March 2026, the sauruslord account published @sauruslord/libsignal version 2.0.1 at 12:40 UTC. Four minutes and 19 seconds later, sauruslord-baileys 2.0.2 appeared at 12:43 UTC. The sub-5-minute gap establishes a coordinated publishing session linking @sauruslord/libsignal directly to the dropper package.
@sauruslord/libsignal names itself after Open Whisper Systems’ Signal protocol library (libsignal-node), a dependency used by @whiskeysockets/baileys for end-to-end encryption. The impersonation is targeted: developers auditing a Baileys-based project who see @sauruslord/libsignal in a dependency tree may assume it is a fork or wrapper of the legitimate Signal library.
What it actually does is documented in the Amazon Inspector analysis attached to MAL-2026-10659. The payload is recovered from the install.js file (SHA-256: 17ea4f900139649f6c1e9c082601673cf8d22c15019ebc265a48c3f4f47b4880).
Payload Analysis: @sauruslord/libsignal
On require() of index.js, after a 1-second delay, install.js executes. It traverses the installer’s node_modules directory to locate the @whiskeysockets/baileys installation and overwrites lib/Socket/newsletter.js with an attacker-supplied stub.
The replacement stub does two things. First, it schedules a setTimeout that fires 120 seconds after the host application starts and silently invokes:
newsletterWMexQuery('120363425694844039@newsletter', QueryIds.FOLLOW)This call uses the already-authenticated WhatsApp session belonging to the application’s user to follow an attacker-controlled WhatsApp newsletter channel with the identifier 120363425694844039@newsletter. The follow happens 120 seconds after startup on every subsequent run of the host application. There is no prompt, no notification, and no visible effect in the WhatsApp UI visible to the user at the moment the follow fires.
Second, install.js schedules process.exit(0) 20 seconds after import. The host application terminates 20 seconds after the package is loaded. This is not a side effect. It is deliberate: the exit gives the installer plausible cover (“the app crashed during setup”) while ensuring the payload ran and the file on disk was rewritten before anything else could interfere.
The original newsletter.js is destroyed. The restoreBackup export referenced in the replacement stub never writes any backup. There is no recovery path short of reinstalling @whiskeysockets/baileys from a clean source.
The package also declares crypto, fs, and path as npm package dependencies rather than referencing them as Node.js builtins. These identifiers do not exist as published npm packages with legitimate functionality. Listing them forces npm to resolve them from the registry, pulling in whatever is registered under those names at install time.
The behavior extracted from the Amazon Inspector sandbox analysis of version 2.0.2, combined with the publish timing pattern, establishes @sauruslord/libsignal as the payload-delivery hub of the Wave 2 cluster.
Wave 2 Version Timeline
| Package | Version | Published (UTC) | Notes |
|---|---|---|---|
sauruslord-baileys | 2.0.0 | 2026-03-15 05:35 | 2.x series opens; 11-day gap from 1.1.9 |
zaldy-baileys | 2.0.0 | 2026-03-23 11:03 | New account; same session as sauruslord-baileys 2.0.1 |
sauruslord-baileys | 2.0.1 | 2026-03-23 11:45 | 42 minutes after zaldy publish |
@sauruslord/libsignal | 2.0.1 | 2026-03-26 12:40 | libsignal impersonation introduced |
sauruslord-baileys | 2.0.2 | 2026-03-26 12:43 | 4 minutes 19 seconds after libsignal; coordinated session |
sauruslord-baileys | 2.0.3 through 2.1.0 | 2026-03-27 to 2026-04-14 | 2.x continues; 8 additional versions |
@sauruslord/libsignal | 2.0.2 | 2026-06-10 19:58 | 58-day gap; libsignal updated; Amazon Inspector confirmed malicious |
sauruslord-baileys | 3.0.0 | 2026-06-10 20:03 | 4 minutes 45 seconds after libsignal 2.0.2; 3.x series launches |
sauruslord-baileys | 3.0.1 | 2026-06-10 20:18 | 15 minutes later |
sauruslord-baileys | 3.0.2 | 2026-06-10 20:32 | 3.x complete within 29 minutes of libsignal update |
The June 10 session is the most concentrated in the campaign. The sauruslord account updated @sauruslord/libsignal, then published three versions of sauruslord-baileys under a new major version scheme in under 30 minutes. The 3.x bump mirrors the version scheme used by @fhkry/x-baileys, which launched the following morning.
Wave 3: The @fhkry Account and 43 Versions in Eight Days (April and June 2026)
Package Anatomy
The fhkry account first appeared on 2 April 2026 with @fhkry/baileys-v2 version 1.0.0, published at 01:07 UTC. The early-morning timestamp for a lone single-version publish, combined with the 1.0.0 version bump while the sauruslord account was mid-campaign on its 2.x series, marks this as account infrastructure preparation.
The package.json metadata recovered from the @fhkry/baileys-v2 1.0.0 version record (still visible in registry metadata before the security hold wiped the tarball) shows the identical preinstall script fingerprint that links it to the sauruslord-baileys payload architecture:
{
"scripts": {
"preinstall": "node ./engine-requirements.js"
}
}The filename engine-requirements.js appears as an Amazon Inspector evidence file in the sauruslord-baileys 3.x advisory and as the preinstall target in @fhkry/baileys-v2. Shared payload filename across two different npm accounts is the binding technical fingerprint connecting the sauruslord and fhkry clusters as one operator.
The fhkry account registered the publisher email styjr13@gmail.com, extracted from the @fhkry/baileys-v2 1.0.0 version metadata. The domain is gmail.com, consistent with a throwaway registration. We checked the styjr13 identifier against the OSSF malicious-packages GitHub repository and the kmsec DPRK research feed and found no prior reporting of this email or username in either source.
@fhkry/x-baileys: 43 Versions, Eight Days
The fhkry account’s most aggressive package is @fhkry/x-baileys, which began publishing at 03:23 UTC on 11 June 2026, seven hours after the Wave 2 libsignal and 3.x sauruslord session closed. Forty-three versions were published across eight days, from 1.0.0 through 6.3.0, with the densest activity on 16 June when 15 versions shipped in a single day.
The version timeline shows the operator pushing through minor version increments in bursts of 10 to 20 minutes before jumping to a new major version. The jump from 2.9.0 to 3.0.0 took three minutes and 28 seconds. The jump from 4.9.0 to 5.0.0 took seven minutes. This is not release management. It is payload generation.
Wave 3 Version Timeline (Selected)
| Package | Version | Published (UTC) | Notes |
|---|---|---|---|
@fhkry/baileys-v2 | 1.0.0 | 2026-04-02 01:07 | Account infrastructure; engine-requirements.js preinstall confirmed |
@fhkry/x-baileys | 1.0.0 | 2026-06-11 03:23 | 7 hours after Wave 2 June session; active iteration begins |
@fhkry/x-baileys | 1.1.0 through 1.7.0 | 2026-06-11 to 2026-06-16 | Minor version chain |
@fhkry/x-baileys | 2.0.0 | 2026-06-16 13:55 | Major bump mid-day |
@fhkry/x-baileys | 2.1.0 through 2.9.0 | 2026-06-16 14:09 to 17:03 | 9 versions in 3 hours |
@fhkry/x-baileys | 3.0.0 | 2026-06-16 17:06 | 3 minutes after 2.9.0 |
@fhkry/x-baileys | 4.9.0 to 5.0.0 | 2026-06-17 07:21 to 15:50 | 8-hour pause before 5.x |
@fhkry/x-baileys | 6.0.0 through 6.3.0 | 2026-06-18 02:33 to 03:12 | Final session; last publish before detection |
The last recorded publish across the entire cluster is @fhkry/x-baileys 6.3.0 at 03:12 UTC on 18 June 2026. The npm security hold across all six packages was applied on 15 July 2026.
OPSEC Failures
The engine-requirements.js filename appears verbatim as both the preinstall target in @fhkry/baileys-v2’s published package.json and as a confirmed malicious evidence file in the sauruslord-baileys 3.x Amazon Inspector report. The operator used the same payload filename across two different npm accounts, directly linking the sauruslord and fhkry identities through a single artifact name. If a different filename had been used for the fhkry packages, the cross-account attribution would have required infrastructure-level corroboration. The shared filename produced it from the package manifest alone.
The @sauruslord/libsignal package also declares crypto, fs, and path as npm dependencies, listing Node.js builtins as registry packages. This is a consistent attacker pattern when the dropper’s dependency tree is generated programmatically without correcting for builtin module names, and it surfaces immediately in any forward dependency audit.
IOC Table
| Indicator | Type | Value | Wave | Method |
|---|---|---|---|---|
sauruslord-baileys | npm package | All versions (1.0.2 through 3.0.2) | 1, 2 | Confirmed malicious in MAL-2026-10661; registry time field audited |
@sauruslord/baileys | npm package | 1.0.0, 1.0.1 | 1 | Confirmed malicious in MAL-2026-10657; registry time field audited |
@sauruslord/libsignal | npm package | 2.0.1, 2.0.2 | 2 | Confirmed malicious in MAL-2026-10659; Amazon Inspector sandbox detonation |
zaldy-baileys | npm package | 2.0.0 | 2 | Confirmed malicious in MAL-2026-10663; registry time field audited |
@fhkry/baileys-v2 | npm package | 1.0.0 | 3 | Confirmed malicious in MAL-2026-10664; preinstall script recovered from registry metadata |
@fhkry/x-baileys | npm package | All versions (1.0.0 through 6.3.0) | 3 | Confirmed malicious in MAL-2026-10665; registry time field audited |
engine-requirements.js | Malicious preinstall payload | SHA-256: 9b0ac7033c5a7f5646f4bdbe08fe542a2d26031fd5f4ca1f082f6972ee383a45 | 1, 2, 3 | Recovered from sauruslord-baileys evidence files (Amazon Inspector); filename confirmed in @fhkry/baileys-v2 registry metadata |
lib/index.js | Malicious module payload | SHA-256: 69a6ca2dcaf905a690fbf65030aa486217975358a54077c7b05bce9cf2bfa1da | 2 | Recovered from sauruslord-baileys 3.x evidence files (Amazon Inspector, MAL-2026-10661) |
install.js | Filesystem implant dropper | SHA-256: 17ea4f900139649f6c1e9c082601673cf8d22c15019ebc265a48c3f4f47b4880 | 2 | Recovered from @sauruslord/libsignal 2.0.2 evidence files (Amazon Inspector, MAL-2026-10659) |
120363425694844039@newsletter | Attacker WhatsApp newsletter channel | WhatsApp channel identifier | 2 | Extracted from Amazon Inspector detonation analysis of @sauruslord/libsignal install.js; reported in MAL-2026-10659 |
lib/Socket/newsletter.js | Overwritten victim file | Path within @whiskeysockets/baileys | 2 | Extracted from Amazon Inspector detonation analysis of @sauruslord/libsignal install.js |
styjr13@gmail.com | Publisher account email | fhkry npm account | 3 | Pulled from @fhkry/baileys-v2 1.0.0 version metadata during registry audit |
sauruslord | npm publisher account | Wave 1 and 2 operator identity | 1, 2 | Pulled from registry metadata _npmUser field across all sauruslord-prefixed packages |
zaldy | npm publisher account | Wave 2 satellite account | 2 | Pulled from registry metadata _npmUser field for zaldy-baileys 2.0.0 |
fhkry | npm publisher account | Wave 3 operator identity | 3 | Pulled from @fhkry/baileys-v2 1.0.0 version metadata |
Affected Versions
| Package | Version | Published (UTC) | Current Status | OSV Entry |
|---|---|---|---|---|
@sauruslord/baileys | 1.0.0 | 2026-03-05 15:18 | Security hold (0.0.1-security) | MAL-2026-10657 |
@sauruslord/baileys | 1.0.1 | 2026-03-05 15:27 | Security hold | MAL-2026-10657 |
sauruslord-baileys | 1.0.2 through 1.1.9 | 2026-03-05 to 2026-03-13 | Security hold (0.0.1-security) | MAL-2026-10661 |
sauruslord-baileys | 2.0.0 through 2.1.0 | 2026-03-15 to 2026-04-14 | Security hold | MAL-2026-10661 |
zaldy-baileys | 2.0.0 | 2026-03-23 11:03 | Security hold (0.0.1-security) | MAL-2026-10663 |
@sauruslord/libsignal | 2.0.1 | 2026-03-26 12:40 | Security hold (0.0.1-security) | MAL-2026-10659 |
@sauruslord/libsignal | 2.0.2 | 2026-06-10 19:58 | Security hold | MAL-2026-10659 |
sauruslord-baileys | 3.0.0 through 3.0.2 | 2026-06-10 20:03 to 20:32 | Security hold | MAL-2026-10661 |
@fhkry/baileys-v2 | 1.0.0 | 2026-04-02 01:07 | Security hold (0.0.1-security) | MAL-2026-10664 |
@fhkry/x-baileys | 1.0.0 through 6.3.0 (43 versions) | 2026-06-11 to 2026-06-18 | Security hold (0.0.1-security) | MAL-2026-10665 |
Remediation
Determine whether any of the six packages appear in package.json, package-lock.json, or node_modules in any project or container image built between 5 March 2026 and 15 July 2026. Check yarn.lock and pnpm-lock.yaml for lockfile entries under the package names above. If any are found:
-
Remove the packages with
npm uninstall <package-name>and delete any cached versions from the npm cache (npm cache clean --force). -
If
@sauruslord/libsignalwas installed in an environment that also contained@whiskeysockets/baileys, treatlib/Socket/newsletter.jswithin the Baileys installation as compromised. Compare it against the canonical version from the WhiskeySockets repository at the version pinned in your lockfile. Reinstall@whiskeysockets/baileysfrom a clean npm install into an isolated directory and replace the file. -
Review all WhatsApp sessions authenticated from any application that loaded
@sauruslord/libsignal. The session was used to follow the attacker-controlled newsletter channel120363425694844039@newsletter. Audit active newsletter subscriptions from the affected WhatsApp account and remove any unfamiliar channels. -
The
fhkryaccount registered under emailstyjr13@gmail.com. If this account name appears in any internal dependency audit tooling or allowlist, remove it. -
Scan pipeline logs and CI artifact caches for any
npm installruns that pulled the affected packages. Treat any environment where these packages were installed as potentially compromised at the WhatsApp session layer, not merely at the package installation layer.
Baileys-based applications authenticate long-lived WhatsApp Web sessions that persist across application restarts. The @sauruslord/libsignal payload exploits this by abusing an already-established session rather than stealing credentials. Credential rotation in the traditional sense does not apply; what requires remediation is the ongoing session itself.
Attack Surface Analysis
@whiskeysockets/baileys has no verified publisher registry. Any npm account can publish a scoped package prefixed with a user-chosen handle (sauruslord, fhkry) and claim Baileys functionality in the package name or description. There is no mechanism short of OSSF scanning or manual review to distinguish a malicious Baileys fork from a legitimate community extension at install time.
The user profile compounds this: Baileys-based applications are typically automation bots or customer service integrations that run with long-lived WhatsApp sessions in unattended server environments. The developer who installs a malicious Baileys variant during local testing may never connect the subsequent unexpected process.exit() to a session compromise. The 120-second delayed follow in the @sauruslord/libsignal payload is calibrated for exactly this: it fires after startup is complete, when the developer has already moved on.
We found no prior reporting of the sauruslord, zaldy, or fhkry accounts in the kmsec DPRK research feed, the OSSF malicious-packages GitHub repository beyond the current advisories, or any Wiz Research, StepSecurity, Unit 42, or Aikido Security publications. The campaign is distinct from the Sha1-Hulud and Miasma worm-style clusters documented in 2025.
