Feed
HighPublished 15 Jul 202625 packages · 56 versions

GitHub Advisory malware sweep — 25 npm packages (6-package `@sauruslord` / `zaldy-baileys` WhatsApp-Baileys-fork cluster, 4-package `webpack-cache-*` / `vite-config-optimizer` 35-day dep-confusion sleeper, `patientdocuments` + `fhirproxy-utils` FHIR/healthcare pair, `@bcs-mi-ui` 3-package internal cluster, `js-shared-modules` scope-pair) retired 2026-07-15

Summary

On 2026-07-15 GitHub's Advisory Database retired 25 CWE-506 npm malware advisories in four clean bursts. Highlights: a 6-package @sauruslord / zaldy-baileys / saurus-assets Baileys WhatsApp-API fork cluster (retired inside a 65-second window at 05:11-05:12 UTC — same operator signature as the earlier @skyzopedia/baileys-mod and lotusbail WhatsApp-message-stealer campaigns), a 4-package webpack-cache-cycle / webpack-session-cache / webpack-cache-reset / vite-config-optimizer 35-day sleeper retired in a 15-second burst, and a healthcare-targeted patientdocuments@75.0.0 + fhirproxy-utils FHIR-namespace dep-confusion pair.

dependency-confusiontyposquatdormant-domaincredential-theftobfuscationinfostealer
Detected by
GitHub Advisory Database · npm Security · Hacktron
Also known as
2026-07-15 GHSA npm sweep · sauruslord Baileys WhatsApp-fork cluster · webpack-cache dep-confusion sleeper
Ecosystems
npm
Packages tracked
25

What happened

On 2026-07-15 GitHub's Advisory Database published 25 CWE-506 (Embedded Malicious Code) advisories against npm packages. Every record uses the standard "any computer that has this package installed or running should be considered fully compromised — rotate all secrets from a different computer" boilerplate. Registry cross-reference against the npm time map revealed sharply distinct clusters, and the retirement timestamps show four coordinated take-down bursts:

Cluster 1 — Baileys WhatsApp-fork credential-stealer cluster (6 packages)

| Package | Observed versions | First publish (UTC) | GHSA replacement (UTC) | |---|---|---|---| | @sauruslord/baileys | 1.0.0, 1.0.1 | 2026-03-05 15:18:54 | 2026-07-15 05:12:04 | | sauruslord-baileys | 44 versions (1.0.23.0.2+) | 2026-03-05 15:40:23 | 2026-07-15 05:12:09 | | saurus-assets | 1.0.0 | 2026-03-12 11:50:07 | 2026-07-15 05:11:53 | | zaldy-baileys | 2.0.0 | 2026-03-23 11:03:38 | 2026-07-15 05:12:50 | | @sauruslord/eslint-config | 2.0.1, 2.0.2 | 2026-03-26 12:40:29 | 2026-07-15 05:12:41 | | @sauruslord/libsignal | 2.0.0 | 2026-03-27 05:13:32 | 2026-07-15 05:12:19 |

All six packages are forks or accessories of @whiskeysockets/baileys, the canonical TypeScript library for WhatsApp Web Multi-Device. sauruslord-baileys is the primary fork (44 point-release versions across Mar 5 → Jul 15 — a legitimate-looking maintenance cadence). @sauruslord/baileys, @sauruslord/libsignal, saurus-assets, zaldy-baileys are the scoped satellites and republishes. @sauruslord/eslint-config shipped a 2.0.2 bump on 2026-06-10 — the same publish date used by the webpack-cache dep-confusion cluster below, which is likely coincidental but worth noting.

All six retired in a ~65-second coordinated npm-Security take-down burst on 2026-07-15 05:11:53 → 05:12:50 UTC — the same operator-signature pattern seen on the 2026-07-13 Spanish-enterprise getd-* retirement.

Threat-model context: WhatsApp-bot supply-chain forks

The Baileys-fork pattern is the same shape as two well-documented earlier campaigns:

  • @skyzopedia/baileys-mod (Xygeni disclosure): from version 8.0.1 onwards, runtime code injection in lib/Socket/newsletter.js silently subscribes the authenticated WhatsApp bot session to attacker-controlled newsletter channels 80 seconds after module load. Payload dynamically fetches its target list from GitHub, making the behavior self-updating and install-time-analysis-resistant.
  • lotusbail (Koi Security disclosure, ~56K downloads): fork of @whiskeysockets/baileys with four-layer obfuscation (Unicode variable manipulation, LZString compression, Base-91 encoding, AES encryption). Hardcoded AES-encrypted pairing code performs a WhatsApp link-device grant to the attacker's device that survives package removal — victims must manually unlink all devices in WhatsApp settings to revoke the attacker's persistent access.

The @sauruslord / sauruslord-baileys / saurus-assets / zaldy-baileys cluster fits the same shape and should be treated with the same threat model: install-time host compromise plus long-lived attacker access to any WhatsApp account the bot was ever paired with.

Cluster 2 — Webpack / Vite -cache- / -config- 35-day dep-confusion sleeper (4 packages)

| Package | Version | Publish (UTC) | GHSA replacement (UTC) | |---|---|---|---| | vite-config-optimizer | 1.1.4 | 2026-06-10 09:48:41 | 2026-07-15 03:40:41 | | webpack-cache-cycle | 0.1.4 | 2026-06-10 08:27:58 | 2026-07-15 03:40:46 | | webpack-cache-reset | 0.1.4 | 2026-06-10 08:02:25 | 2026-07-15 03:40:51 | | webpack-session-cache | 0.1.4 | 2026-06-10 07:38:35 | 2026-07-15 03:40:56 |

All four packages published within a 50-minute window on 2026-06-10 07:38 → 09:48 UTC, dormant for 35 days, then retired in a 15-second npm-Security take-down burst on 2026-07-15 03:40:41 → 03:40:56 UTC.

Deceptive packaging — same operator across both namespaces

Hacktron's analysis of vite-config-optimizer@1.1.4 documents the attacker's cross-namespace tell: the vite-config-optimizer package.json declares its repository field as webpack-tools/webpack-cache-plugin and its main module exports a WebpackCachePlugin class. The vite-* slug is cover: the actual payload identifies as webpack tooling. This ties the vite-config-optimizer publish directly to the webpack-cache-cycle / webpack-cache-reset / webpack-session-cache triplet — the four names are the SAME operator broadening the dep-confusion catchment across both major bundler ecosystems.

Payload chain (from the Hacktron analysis)

  1. postinstall hook triggers loader.js on every npm install.
  2. loader.js spawns a detached child Node process running a dropper — child.unref() hides the running dropper from the installer's process tree.
  3. Dropper decodes a hidden URL via Buffer.from(<hex-literal>, 'hex').toString() — evades plain-text URL scanners that grep tarballs for http(s):// strings.
  4. Fetches second-stage over HTTPS, writes it to a temp file, executes it inline with the installer's privileges.

No write-up exists for the three webpack-* packages but the shared operator makes it a safe bet the payload is identical or near-identical.

Cluster 3 — Healthcare / FHIR dep-confusion pair (2 packages)

| Package | Version | Publish (UTC) | GHSA replacement (UTC) | |---|---|---|---| | patientdocuments | 75.0.0 | 2026-05-31 17:08:31 | 2026-07-15 02:30:11 | | fhirproxy-utils | 1.0.8 | 2026-05-31 12:14:47 | 2026-07-15 01:55:01 |

Both patientdocuments and fhirproxy-utils are internal-scope-shape names likely targeting a specific healthcare provider's internal Node.js integration project. The patientdocuments@75.0.0 version pin is the fingerprint of a dep-confusion version-race: shipping a conspicuously high major version guarantees the malicious tarball beats any legitimate internal package resolution when the installer falls through to the public registry.

The fhirproxy-utils name aligns with the HL7 Fast Healthcare Interoperability Resources ecosystem, which is publicly documented as historically susceptible to dep-confusion attacks because FHIR packages resolved through non-standard registries and were only pre-registered on npm as defensive stubs after the March 2026 HL7 security notice.

Cluster 4 — @bcs-mi-ui internal-scope cluster (3 packages)

| Package | Version | Publish (UTC) | GHSA replacement (UTC) | |---|---|---|---| | @bcs-mi-ui/message | 1.0.2 | 2026-05-17 16:06:52 | 2026-07-15 03:31:52 | | @bcs-mi-ui/message-block | 1.0.2 | 2026-05-17 16:14:21 | 2026-07-15 03:32:01 | | @bcs-mi-ui/test1243npmpacket76 | 1.0.2 | 2026-05-24 11:40:20 | 2026-07-15 03:32:10 |

The @bcs-mi-ui scope shape (bcs-mi UI) points to an internal enterprise UI-component project. The test1243npmpacket76 slug is the fingerprint of a leftover dep-confusion research/test push that got weaponized alongside the two production-looking message and message-block components. Retired in a ~20-second npm-Security take-down burst on 2026-07-15 03:31:52 → 03:32:10 UTC.

Cluster 5 — js-shared-modules scope-pair (2 packages)

| Package | Version | Publish (UTC) | GHSA replacement (UTC) | |---|---|---|---| | @saladin0x1/js-shared-modules | 1.11.6 | 2026-05-24 18:17:05 | 2026-07-15 02:47:15 | | js-shared-modules | 1.11.6, 1.11.7 | 2026-05-24 18:20:33 | 2026-07-15 02:47:05 |

Classic dep-confusion scope-pair: a scoped package on a personal namespace (@saladin0x1/js-shared-modules) republished as an unscoped variant on the public registry. Any installer with scope-fallthrough behavior against an @saladin0x1 internal-registry pin resolves the malicious unscoped tarball.

Cluster 6 — Assorted singletons (8 packages)

| Package | Versions | Publish window (UTC) | GHSA replacement (UTC) | |---|---|---|---| | ssweb-wp | 1.0.0 | 2026-06-03 12:42:48 | 2026-07-15 05:12:45 | | ldpbootstrap-jquery | 17 versions 1.0.01.0.16 | 2026-06-09 → 2026-06-14 | 2026-07-15 03:57:36 | | testzapier | 1.0.0, 1.0.1 | 2026-06-04 17:10:37 → 17:18:20 | 2026-07-15 03:38:24 | | gpu-accelerator | 1.4.21.4.7 | 2026-06-11 → 2026-06-12 | 2026-07-15 03:35:12 | | textshape-css | 1.0.0 | 2026-06-19 05:54:02 | 2026-07-15 03:35:22 | | postcss-processor-utils | 1.0.01.0.3 | 2026-06-10 12:38:40 → 20:21:31 | 2026-07-15 03:35:17 | | @achuthvp/postinstall-poc | 1.0.01.0.3 | 2026-05-29 → 2026-06-03 | 2026-07-15 03:33:42 | | @hkyyy/portal-widget-helper-0601 | 1.0.0 | 2026-06-01 08:07:25 | 2026-07-15 02:52:41 |

Names span WordPress-adjacent (ssweb-wp), Linked-Data-Platform typosquat (ldpbootstrap-jquery), Zapier integration target (testzapier), generic ML/CUDA (gpu-accelerator), PostCSS tooling (postcss-processor-utils, textshape-css), self-labeled proof-of-concept (@achuthvp/postinstall-poc — GHSA treats it as live malware regardless of the honest slug), and an internal-scope helper (@hkyyy/portal-widget-helper-0601 — the 0601 suffix likely reflects a dated internal-registry name pattern).

Contrast with recent sweeps

| Date | Packages | Notes | |---|---|---| | 2026-07-06 | ~155 | Largest 2026 sweep | | 2026-07-07 | ~65 | AI-SDK typosquats + Solana base58 | | 2026-07-08 | ~20 | Claude-Code typosquat cluster | | 2026-07-10 (early) | 25 | Epic Games / LuminaryCloud / Voyager dep-confusion + nodemon family | | 2026-07-10 (late) / 2026-07-11 | 11 | Higher Logic / AT&T eBiz / Amtrav / babel-eslint dep-confusion + type-* 3.3.7 cluster + auth-typosquats | | 2026-07-13 | 14 | Spanish-enterprise getd-* 40-day dep-confusion sleeper (10) + pure-folder-three poisoned bump + dotnet-runtime-base + node-sysmetrics + @jplopezy/connectivity-test-do-not-install | | 2026-07-15 | 25 | Baileys WhatsApp-fork credential-stealer cluster (6) + webpack/vite -cache- 35-day dep-confusion sleeper (4) + FHIR healthcare pair (2) + @bcs-mi-ui internal cluster (3) + js-shared-modules scope-pair (2) + 8 singletons |

The running July 1–15 npm-malware retirement count is ~345 packages across 11 GHSA sweeps.

Registry state

Every package now resolves to a 0.0.1-security holding tarball owned by npm Security. Historical version tarballs may remain fetchable from the CDN for 24–72 hours after the security replacement lands and should be treated as live malware in any lockfile hit — regardless of exact version. Because the security replacement wipes the historical version list from the public registry response, the versions map below records the concrete versions observed pre-replacement via npm registry time-object inspection.

Affected packages (25)

  • npm@achuthvp/postinstall-poc
    1.0.01.0.11.0.21.0.3
  • npm@bcs-mi-ui/message
    1.0.2
  • npm@bcs-mi-ui/message-block
    1.0.2
  • npm@bcs-mi-ui/test1243npmpacket76
    1.0.2
  • npm@hkyyy/portal-widget-helper-0601
    1.0.0
  • npm@saladin0x1/js-shared-modules
    1.11.6
  • npm@sauruslord/baileys
    1.0.01.0.1
  • npm@sauruslord/eslint-config
    2.0.12.0.2
  • npm@sauruslord/libsignal
    2.0.0
  • npmfhirproxy-utils
    1.0.8
  • npmgpu-accelerator
    1.4.21.4.31.4.41.4.51.4.61.4.7
  • npmjs-shared-modules
    1.11.61.11.7
  • npmldpbootstrap-jquery
    1.0.01.0.21.0.31.0.41.0.51.0.61.0.71.0.91.0.101.0.111.0.121.0.131.0.141.0.151.0.16
  • npmpatientdocuments
    75.0.0
  • npmpostcss-processor-utils
    1.0.01.0.11.0.21.0.3
  • npmsaurus-assets
    1.0.0
  • npmsauruslord-baileys
    1.0.22.0.03.0.2
  • npmssweb-wp
    1.0.0
  • npmtestzapier
    1.0.01.0.1
  • npmtextshape-css
    1.0.0
  • npmvite-config-optimizer
    1.1.4
  • npmwebpack-cache-cycle
    0.1.4
  • npmwebpack-cache-reset
    0.1.4
  • npmwebpack-session-cache
    0.1.4
  • npmzaldy-baileys
    2.0.0

Impact

  • Any host that installed any of the 25 packages listed below should be treated as fully compromised — every GHSA record uses the boilerplate CWE-506 "rotate all secrets from a different computer" language, and no patched version exists for any of them
  • Baileys WhatsApp-fork credential-stealer cluster (6 packages): @sauruslord/baileys, @sauruslord/libsignal, @sauruslord/eslint-config, saurus-assets, sauruslord-baileys, zaldy-baileys. All are typosquats or forks of the widely-used @whiskeysockets/baileys WhatsApp Multi-Device Web API library and its signal-protocol helpers. The pattern matches the earlier @skyzopedia/baileys-mod disclosure (Xygeni, runtime code injection in lib/Socket/newsletter.js that auto-subscribes the authenticated WhatsApp bot session to attacker-controlled newsletter channels 80s after module load) and the lotusbail disclosure (Koi Security, ~56K downloads, four-layer obfuscation, hardcoded AES-encrypted pairing code that link-devices the victim's WhatsApp session to the attacker permanently). sauruslord-baileys shipped 44 versions across Mar 5 → Jul 15 as a maintained fork before retirement. Impact is not just install-time host compromise — the attacker gets long-lived access to victim WhatsApp accounts (link-device grant survives package removal; victims must manually unlink devices in WhatsApp settings)
  • Webpack / Vite -cache- / -config- dep-confusion sleeper cluster (4 packages): webpack-cache-cycle, webpack-session-cache, webpack-cache-reset (all 0.1.4 published 2026-06-10), vite-config-optimizer (1.1.4 published 2026-06-10). All four retired in a 15-second take-down burst on 2026-07-15 03:40:41 → 03:40:56 UTC. Hacktron's analysis of vite-config-optimizer@1.1.4 documents the payload: a postinstall hook triggers loader.js, which spawns a detached child Node process running a dropper that hex-decodes a hidden URL via Buffer.from(..., 'hex').toString() (evades plain-text URL scanners), fetches the second-stage over HTTPS, writes it to a temp file, and executes arbitrary attacker-controlled JS inside the installer's Node process with installer privileges. Deceptive packaging: the vite-config-optimizer package.json declares its repository as webpack-tools/webpack-cache-plugin and its main module exports a WebpackCachePlugin class — the four packages are the SAME operator publishing under both webpack-* and vite-* namespaces to broaden the dep-confusion catchment (35-day dormancy Jun 10 → Jul 15 is deliberate ambient tactics identical to the Spanish-enterprise getd-* cluster retired 2026-07-13)
  • Healthcare / FHIR dep-confusion pair (2 packages): patientdocuments@75.0.0 (published 2026-05-31, note the conspicuously high major version 75.x — a classic dep-confusion version-race pin designed to beat any legitimate internal package on npm install semver resolution) and fhirproxy-utils@1.0.8 (published 2026-05-31). Both point to a targeted campaign against a specific healthcare provider's internal npm namespace. FHIR (Fast Healthcare Interoperability Resources) is the HL7 healthcare-data standard whose npm packages are publicly documented as susceptible to dependency-confusion attacks because FHIR packages historically resolved through non-standard registries. Any HL7-based healthcare integration project that had patientdocuments or fhirproxy-utils unscoped in its dependency graph resolved these malicious tarballs
  • @bcs-mi-ui internal-scope cluster (3 packages): @bcs-mi-ui/message, @bcs-mi-ui/message-block, @bcs-mi-ui/test1243npmpacket76 — all 1.0.2 published mid-to-late May 2026, retired in a 20-second window on 2026-07-15 03:31:52 → 03:32:10 UTC. The test1243npmpacket76 slug is the fingerprint of a dep-confusion research/test push that got weaponized: a real attacker publishing under @bcs-mi-ui picked up the scope name, kept the leftover test-shaped slug alongside, and shipped a poisoned message component that a bcs-mi enterprise UI project would resolve via unscoped fallthrough
  • js-shared-modules scope-pair dep-confusion (2 packages): @saladin0x1/js-shared-modules@1.11.6 (scoped) + js-shared-modules@1.11.6,1.11.7 (unscoped) both published 2026-05-24 → 2026-05-31 and retired 2026-07-15 02:47 UTC. Classic dep-confusion pattern: a legitimate scoped internal package gets shadowed by a maliciously-published unscoped variant on the public registry, hoping the installer misresolves
  • Assorted singletons (8 packages) — ssweb-wp (WordPress-adjacent, 1.0.0 2026-06-03), ldpbootstrap-jquery (17 versions Jun 9-14, linked-data-platform-shape typosquat), testzapier (2 versions Jun 4, Zapier integration target), gpu-accelerator (6 versions 1.4.21.4.7 Jun 11-12, generic ML/CUDA name), textshape-css (1.0.0 Jun 19), postcss-processor-utils (4 versions Jun 10 with a rapid 1.0.0 → 1.0.3 burst), @achuthvp/postinstall-poc (4 versions late May–early Jun, self-labeled POC that GHSA treats as live malware regardless), @hkyyy/portal-widget-helper-0601 (1.0.0 2026-06-01, internal-scope shape). Every retirement is a 0.0.1-security npm-Security replacement
  • No payload write-up accompanies most of the GHSA texts (only vite-config-optimizer has a public IOC analysis via Hacktron) — defenders should treat install-time behavior as unanalyzed for the other 24 packages and assume worst case for any host that resolved these names

What to do

  1. 1Grep every lockfile (package-lock.json, yarn.lock, pnpm-lock.yaml) for each name in the packages map below. Any match is a supply-chain incident: rotate every credential the build runner could reach and re-image the build host
  2. 2*If your WhatsApp bot / automation project imports any Baileys fork under `@sauruslord/, sauruslord-baileys, zaldy-baileys, or saurus-assets**: replace with the canonical [@whiskeysockets/baileys`](https://www.npmjs.com/package/@whiskeysockets/baileys) fork upstream. Manually unlink every device from WhatsApp settings on any WhatsApp number the bot was ever paired with — the attacker-controlled pairing device persists after package removal, matching the Koi Security lotusbail disclosure pattern. Assume every message sent/received during the exposure window was exfiltrated
  3. 3If you had any of webpack-cache-cycle, webpack-session-cache, webpack-cache-reset, or vite-config-optimizer in a lockfile: none of these have legitimate parents on npm. The webpack build cache is a first-party feature; the canonical Vite tooling never publishes under vite-config-optimizer. Remove the dependencies. Because the payload spawns a detached unref'd child process, the malicious loader may still be running after npm uninstall — reboot the affected host and rotate any credential accessible from it
  4. 4If your organization ships FHIR / HL7-based healthcare integrations and had patientdocuments or fhirproxy-utils in a lockfile: this is a targeted campaign against your internal namespace. Follow the HL7 FHIR dependency-confusion mitigations: use --ignore-scripts for all FHIR-adjacent installs, prefer the Firely terminal / FHIR validator to the raw npm client, and pin internal packages under an org-scoped namespace with .npmrc scope-registry routing (@yourorg:registry=https://internal/)
  5. 5*If you had `@bcs-mi-ui/, @saladin0x1/js-shared-modules, js-shared-modules, or @hkyyy/portal-widget-helper-0601 in a lockfile**: these are internal-scope dep-confusion shots. Audit for scope-fallthrough behavior; pin the internal registry as the primary source for all @bcs-mi-ui, @saladin0x1, @hkyyy scopes via .npmrc`. Register the scopes as defensive stubs on the public registry
  6. 6If you had any singleton in a lockfile (ssweb-wp, ldpbootstrap-jquery, testzapier, gpu-accelerator, textshape-css, postcss-processor-utils, @achuthvp/postinstall-poc): none have legitimate first-party parents. Remove; treat as a supply-chain incident
  7. 7Verify none of the 25 listed packages still resolves via your private mirror — internal Artifactory / Nexus / Verdaccio instances routinely cache tarballs and will keep serving the malicious versions after the public yank, especially for the 35-day-dormant webpack-cache-* cluster whose names had 5+ weeks to be cached by pre-warm pipelines
  8. 8For projects using postinstall-scripting packages, consider running npm install --ignore-scripts in CI as a defense-in-depth measure and re-invoking scripts only for vetted first-party packages (the upcoming npm v12 defaults do this, per the npm v12 announcement)

References

npm-2026-07-15-ghsa-malware-sweep