Back to Intelligence

PhantomSub Campaign: 101 Malicious npm Packages Weaponize Baileys to Hijack Developers' WhatsApp Accounts — Detection and Remediation Guide

SA
Security Arsenal Team
September 29, 2026
13 min read

OX Security researchers Nir Zadok, Moshe Siman Tov Bustan, and Vitalii Chepurko have disclosed a coordinated supply-chain campaign — tracked as PhantomSub — consisting of 101 malicious npm packages designed to silently add developers' WhatsApp accounts to attacker-controlled groups without consent. The packages abuse Baileys, the popular open-source WhatsApp Web API library, turning a routine npm install into an account-compromise event.

This is not a vulnerability in the traditional CVE sense. There is no patch to apply. The malicious packages are functioning as designed — the attack vector is the trust developers place in the npm ecosystem. That makes this a pure detection-and-hygiene problem, and it lands squarely on SOC teams, AppSec engineers, and anyone responsible for build pipelines. If a developer in your organization installed one of these packages, their WhatsApp account — and potentially linked session credentials — is now exposed to a threat actor.

Severity is high for two reasons. First, developer workstations and CI/CD runners are high-value targets: they hold source code, cloud credentials, SSH keys, and signing material. Second, WhatsApp account manipulation at this scale suggests the operators are building a distribution or social-engineering network — compromised developer accounts become launchpads for the next wave.

Technical Analysis

How the PhantomSub Attack Chain Works

Based on the OX Security research, the campaign follows a pattern we've seen repeatedly in npm ecosystem abuse, but with a novel payload objective:

  1. Package publication. The operators published 101 packages to the npm registry. These are typically typosquats, dependency-confusion candidates, or plausible-sounding utility packages designed to be installed accidentally or pulled in transitively.
  2. Install-time execution. Malicious npm packages almost universally execute payload code via lifecycle hooks — preinstall, install, or postinstall scripts defined in package.json. When a developer (or a CI runner) executes npm install, npm spawns a shell that runs the attacker-controlled script with the installing user's privileges.
  3. Baileys abuse. Baileys is a legitimate, widely used open-source library that implements the WhatsApp Web multi-device protocol in TypeScript/JavaScript. It allows programmatic authentication to WhatsApp via QR-code pairing and maintains session state on disk (auth credentials, app-state sync keys, and pre-keys, typically stored as JSON files such as creds.json inside an auth-state directory). The malicious packages leverage Baileys to establish an authenticated WhatsApp session and programmatically add the victim's account to attacker-controlled groups — without the victim's knowledge or consent.
  4. Outcome. The victim is subscribed to WhatsApp groups controlled by the operator. Beyond the immediate privacy violation, this creates a channel for phishing, malware delivery, and social engineering aimed at developers — and it signals that session material may have been harvested.

Affected Products and Platforms

  • npm registry users — any developer or build system that installed one of the 101 malicious packages
  • The Baileys library itself is not vulnerable — it is legitimate software being abused as a weapon, similar to how curl or requests are abused by malware
  • Platforms: All operating systems where Node.js/npm runs (Windows, macOS, Linux) and CI/CD runners that execute npm install
  • WhatsApp accounts tied to phone numbers used by affected developers

Exploitation Status

This is confirmed active, in-the-wild abuse. The 101 packages were live in the npm registry at the time of disclosure. No CVE identifier has been assigned (this is a malicious-package campaign, not a software flaw), and it is not a CISA KEV candidate in the traditional sense. Treat it as an active supply-chain intrusion vector.

Why This Matters Beyond WhatsApp

A package that can execute arbitrary code at install time can do anything the installing user can do. The WhatsApp group subscription is the disclosed payload — but any package with a postinstall hook could equally exfiltrate ~/.ssh, ~/.aws/credentials, .npmrc tokens, or environment variables from CI runners. If you find one of these packages in your environment, scope the investigation to full developer-workstation compromise, not just the WhatsApp behavior.

Detection & Response

Sigma Rules

The following rules target the two most reliable observables from this campaign: (1) npm lifecycle-hook execution spawning shells and Node processes on endpoints, and (2) Node.js processes establishing network connections to WhatsApp infrastructure from developer/build hosts, where no legitimate WhatsApp automation should exist.

YAML
---
title: NPM Lifecycle Hook Spawning Suspicious Child Process
id: 3f7a2c14-9b1e-4d58-a6c2-8e1f5b3d7a90
status: experimental
description: Detects npm or node spawning shell interpreters or script engines during package install lifecycle hooks, consistent with malicious npm packages executing postinstall payloads such as the PhantomSub campaign.
references:
  - https://thehackernews.com/2026/09/101-malicious-npm-packages-add.html
  - https://attack.mitre.org/techniques/T1195/002/
author: Security Arsenal
date: 2026/09/25
tags:
  - attack.execution
  - attack.t1059
  - attack.supply_chain_compromise
  - attack.t1195.002
logsource:
  category: process_creation
  product: windows
detection:
  selection_parent:
    ParentImage|endswith:
      - '\npm.cmd'
      - '\npm.exe'
      - '\node.exe'
      - '\npm'
  selection_child:
    Image|endswith:
      - '\cmd.exe'
      - '\powershell.exe'
      - '\pwsh.exe'
      - '\wscript.exe'
      - '\cscript.exe'
      - '\mshta.exe'
      - '\curl.exe'
      - '\certutil.exe'
  condition: selection_parent and selection_child
falsepositives:
  - Legitimate packages with native compilation steps (node-gyp) may spawn cmd.exe during install
level: high
---
title: Node.js Process Connecting to WhatsApp Infrastructure
id: 8c2e5b71-4a3d-4f69-b1c8-2d7e9a4f6b05
status: experimental
description: Detects Node.js processes establishing network connections to WhatsApp Web infrastructure. The PhantomSub campaign abuses the Baileys library, which communicates with WhatsApp servers. On developer workstations and build servers, Node processes talking to WhatsApp endpoints are highly anomalous.
references:
  - https://thehackernews.com/2026/09/101-malicious-npm-packages-add.html
  - https://attack.mitre.org/techniques/T1102/
author: Security Arsenal
date: 2026/09/25
tags:
  - attack.command_and_control
  - attack.t1102
logsource:
  category: network_connection
  product: windows
detection:
  selection_image:
    Image|endswith:
      - '\node.exe'
      - '\node'
  selection_dest:
    DestinationHostname|contains:
      - 'whatsapp.net'
      - 'whatsapp.com'
  condition: selection_image and selection_dest
falsepositives:
  - Organizations legitimately building WhatsApp Business integrations with Baileys — scope these to known integration servers and exclude
level: high
---
title: Baileys WhatsApp Session Auth State Creation
id: 5d1f8a36-7c42-4e9b-a3d5-6b8c2e1f9a47
status: experimental
description: Detects creation of Baileys WhatsApp session credential files (creds.json and app-state-sync keys) outside of known legitimate integration directories. PhantomSub packages persist WhatsApp sessions on disk to maintain unauthorized group subscription access.
references:
  - https://thehackernews.com/2026/09/101-malicious-npm-packages-add.html
  - https://attack.mitre.org/techniques/T1552/
author: Security Arsenal
date: 2026/09/25
tags:
  - attack.credential_access
  - attack.t1552
logsource:
  category: file_event
  product: windows
detection:
  selection:
    TargetFilename|contains:
      - 'creds.json'
      - 'app-state-sync-key'
      - 'app-state-sync-version'
      - 'auth_info'
  filter_known_paths:
    TargetFilename|contains:
      - '\known-baileys-integration\'
  condition: selection and not filter_known_paths
falsepositives:
  - Legitimate Baileys development — maintain an allowlist of known integration project paths
level: medium

KQL Hunt (Microsoft Sentinel / Defender)

This query hunts for the two primary PhantomSub observables across your endpoint fleet: npm lifecycle execution chains and Node processes reaching WhatsApp infrastructure. Run it over at least 30 days — malicious packages may have been installed weeks before disclosure.

KQL — Microsoft Sentinel / Defender
let lookback = 30d;
// Part 1: npm/node spawning shell or LOLBin child processes (lifecycle hook execution)
let SuspiciousInstall = DeviceProcessEvents
| where TimeGenerated > ago(lookback)
| where InitiatingProcessFileName in~ ("npm.cmd", "npm.exe", "node.exe", "npm")
| where FileName in~ ("cmd.exe", "powershell.exe", "pwsh.exe", "mshta.exe", "wscript.exe", "cscript.exe", "curl.exe", "certutil.exe")
| project TimeGenerated, DeviceName, AccountName, InitiatingProcessCommandLine, FileName, ProcessCommandLine, InitiatingProcessFolderPath;
// Part 2: node.exe connecting to WhatsApp infrastructure (Baileys abuse)
let WhatsAppBeacon = DeviceNetworkEvents
| where TimeGenerated > ago(lookback)
| where InitiatingProcessFileName =~ "node.exe"
| where RemoteUrl has_any ("whatsapp.net", "whatsapp.com")
| project TimeGenerated, DeviceName, InitiatingProcessCommandLine, RemoteUrl, RemoteIP, RemotePort;
// Part 3: Baileys session credential files written to disk
let BaileysAuthState = DeviceFileEvents
| where TimeGenerated > ago(lookback)
| where FileName has_any ("creds.json", "app-state-sync-key", "auth_info")
| where FolderPath has_any ("node_modules", "\\Temp\\", "\\AppData\\")
| project TimeGenerated, DeviceName, FileName, FolderPath, InitiatingProcessFileName, InitiatingProcessCommandLine;
// Union results
union SuspiciousInstall, WhatsAppBeacon, BaileysAuthState
| sort by TimeGenerated desc

For Linux build runners ingested via Syslog, add a companion hunt against shell execution under npm processes:

KQL — Microsoft Sentinel / Defender
Syslog
| where TimeGenerated > ago(30d)
| where ProcessName has_any ("npm", "node")
| where SyslogMessage has_any ("postinstall", "preinstall", "baileys", "whatsapp", "creds.json")
| project TimeGenerated, Computer, ProcessName, SyslogMessage
| sort by TimeGenerated desc

Velociraptor VQL Hunt

This artifact triages endpoints for evidence of PhantomSub activity: Baileys presence inside node_modules trees, WhatsApp session auth-state files, and running Node processes with WhatsApp-related command lines.

VQL — Velociraptor
-- PhantomSub / Baileys abuse triage artifact
-- Hunts for Baileys installations, WhatsApp auth-state files, and suspicious node processes

LET proc_hunt = SELECT Pid, Name, CommandLine, Exe, Username, CreateTime
FROM pslist()
WHERE Name =~ '(?i)node'
  AND CommandLine =~ '(?i)(baileys|whatsapp|postinstall|preinstall)'

LET auth_state = SELECT FullPath, Size, Mtime, Btime
FROM glob(globs=[
  'C:/Users/*/**/creds.json',
  'C:/Users/*/**/app-state-sync-key-*',
  'C:/Users/*/**/auth_info*/**',
  'C:/Users/*/AppData/**/baileys*/**'
])

LET baileys_modules = SELECT FullPath, Size, Mtime
FROM glob(globs=[
  'C:/Users/*/**/node_modules/@whiskeysockets/baileys/**',
  'C:/Users/*/**/node_modules/baileys/**'
])

SELECT * FROM proc_hunt
UNION ALL
SELECT NULL AS Pid, 'FILE:' + FullPath AS Name, '' AS CommandLine,
       FullPath AS Exe, '' AS Username, Mtime AS CreateTime
FROM auth_state

A positive hit on auth_state or baileys_modules on a machine with no sanctioned WhatsApp integration is a strong compromise indicator — collect the directory, identify the parent package that introduced Baileys, and pivot to full host triage.

Remediation and Verification Script

Run this on developer workstations and build agents to inventory npm projects for Baileys presence and suspicious lifecycle hooks. It does not delete anything — it surfaces findings for triage.

Bash / Shell
#!/bin/bash
# PhantomSub / malicious npm package audit
# Scans for Baileys dependencies, lifecycle hooks, and WhatsApp session artifacts

SEARCH_ROOT="${1:-$HOME}"
REPORT="$HOME/npm_phantomsub_audit_$(date +%Y%m%d_%H%M%S).txt"

echo "=== PhantomSub npm Audit - $(hostname) - $(date) ===" | tee "$REPORT"

# 1. Find all package-lock.json / yarn.lock files referencing Baileys
echo -e "\n[1] Projects with Baileys dependency (direct or transitive):" | tee -a "$REPORT"
find "$SEARCH_ROOT" -maxdepth 6 \( -name "package-lock.json" -o -name "yarn.lock" -o -name "pnpm-lock.yaml" \) 2>/dev/null | while read -r lockfile; do
  if grep -qi "baileys" "$lockfile"; then
    echo "  HIT: $lockfile" | tee -a "$REPORT"
    grep -i "baileys" "$lockfile" | head -5 | tee -a "$REPORT"
  fi
done

# 2. Find installed Baileys modules on disk
echo -e "\n[2] Installed Baileys packages in node_modules:" | tee -a "$REPORT"
find "$SEARCH_ROOT" -maxdepth 8 -type d -iname "*baileys*" -path "*node_modules*" 2>/dev/null | tee -a "$REPORT"

# 3. Flag package.json files with lifecycle hooks (preinstall/install/postinstall)
echo -e "\n[3] package.json files with install lifecycle hooks (review manually):" | tee -a "$REPORT"
find "$SEARCH_ROOT" -maxdepth 6 -name "package.json" 2>/dev/null | while read -r pkg; do
  if grep -qE '"(preinstall|install|postinstall)"' "$pkg"; then
    echo "  HOOK: $pkg" | tee -a "$REPORT"
    grep -E '"(preinstall|install|postinstall)"' "$pkg" | tee -a "$REPORT"
  fi
done

# 4. Hunt for WhatsApp session auth-state artifacts on disk
echo -e "\n[4] WhatsApp/Baileys session artifacts (creds.json, app-state-sync):" | tee -a "$REPORT"
find "$SEARCH_ROOT" /tmp -maxdepth 8 \( -name "creds.json" -o -name "app-state-sync-key-*" -o -name "auth_info*" \) 2>/dev/null | grep -v -E "(known|approved)-integration" | tee -a "$REPORT"

# 5. Check for established connections to WhatsApp infrastructure from node
echo -e "\n[5] Active node process connections to WhatsApp infrastructure:" | tee -a "$REPORT"
if command -v ss >/dev/null 2>&1; then
  ss -tnp 2>/dev/null | grep -i "node" | tee -a "$REPORT"
fi

# 6. npm audit on discovered projects
echo -e "\n[6] Running npm audit on discovered project roots..." | tee -a "$REPORT"
find "$SEARCH_ROOT" -maxdepth 4 -name "package.json" -not -path "*node_modules*" 2>/dev/null | while read -r pkg; do
  dir=$(dirname "$pkg")
  echo "  Auditing: $dir" | tee -a "$REPORT"
  (cd "$dir" && npm audit --audit-level=moderate 2>/dev/null | tail -5 | tee -a "$REPORT")
done

echo -e "\n=== Audit complete. Report saved to $REPORT ===" | tee -a "$REPORT"
echo "If sections 1, 2, or 4 produced hits on machines with no sanctioned WhatsApp integration, isolate the host and begin IR scoping."

For Windows developer workstations, the equivalent PowerShell triage:

PowerShell
# PhantomSub audit for Windows developer workstations
$root = "C:\Users"
$report = "$env:USERPROFILE\Desktop\phantomsub_audit_$(Get-Date -Format yyyyMMdd_HHmmss).txt"

"=== PhantomSub npm Audit - $env:COMPUTERNAME ===" | Out-File $report

# 1. Baileys references in lockfiles
"`n[1] Baileys in lockfiles:" | Out-File $report -Append
Get-ChildItem -Path $root -Recurse -Depth 6 -Include "package-lock.json","yarn.lock","pnpm-lock.yaml" -ErrorAction SilentlyContinue |
  Where-Object { (Get-Content $_.FullName -Raw -ErrorAction SilentlyContinue) -match '(?i)baileys' } |
  ForEach-Object { "  HIT: $($_.FullName)" | Out-File $report -Append }

# 2. Installed Baileys modules
"`n[2] Baileys in node_modules:" | Out-File $report -Append
Get-ChildItem -Path $root -Recurse -Depth 8 -Directory -Filter "*baileys*" -ErrorAction SilentlyContinue |
  Where-Object { $_.FullName -match 'node_modules' } |
  ForEach-Object { "  $($_.FullName)" | Out-File $report -Append }

# 3. WhatsApp session artifacts
"`n[3] WhatsApp session artifacts:" | Out-File $report -Append
Get-ChildItem -Path $root -Recurse -Depth 8 -Include "creds.json","app-state-sync-key-*","auth_info*" -ErrorAction SilentlyContinue |
  ForEach-Object { "  $($_.FullName)  LastWrite: $($_.LastWriteTime)" | Out-File $report -Append }

# 4. Node processes with WhatsApp connections
"`n[4] Node processes with WhatsApp connections:" | Out-File $report -Append
Get-NetTCPConnection -State Established -ErrorAction SilentlyContinue |
  Where-Object { (Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).ProcessName -eq 'node' } |
  ForEach-Object {
    $dns = (Resolve-DnsName $_.RemoteAddress -ErrorAction SilentlyContinue).NameHost
    if ($dns -match 'whatsapp') { "  PID $($_.OwningProcess) -> $($_.RemoteAddress) ($dns)" | Out-File $report -Append }
  }

Write-Host "Audit complete: $report"

Remediation

Immediate actions (first 24 hours):

  1. Inventory your dependency trees. Run the audit scripts above across developer workstations and CI runners. Also query your artifact/dependency management platform (Artifactory, Nexus, GitHub Dependabot data, SCA tooling) for any of the 101 package names — pull the IOC package list from the OX Security research and The Hacker News disclosure.
  2. Contain affected hosts. Any machine with a confirmed malicious package install must be treated as fully compromised: revoke and rotate all credentials reachable from that host — SSH keys, cloud IAM tokens (AWS/Azure/GCP), .npmrc tokens, Git credentials, browser sessions, and signing keys.
  3. Revoke WhatsApp sessions. Affected users should open WhatsApp → Settings → Linked Devices and log out all unrecognized sessions, then re-register two-step verification. Report the unauthorized group additions to WhatsApp and exit/report the groups.
  4. Purge the packages. Remove the malicious packages and run a clean install from a known-good lockfile. Do not simply npm uninstall — lifecycle hooks may have dropped persistence; rebuild from a clean checkout or reimage.

Structural hardening (this quarter):

  1. Disable lifecycle scripts by default. Set ignore-scripts=true in user and CI .npmrc files, and explicitly re-enable only for vetted packages that require native builds. This single control kills the vast majority of npm install-time malware.
  2. Lock and pin dependencies. Enforce committed lockfiles with integrity hashes (npm ci in pipelines, never npm install).
  3. Deploy an npm proxy/firewall. Route all package installs through a private registry (Artifactory, Nexus, or a Socket/Phylum-style package firewall) that blocks packages by age, reputation, and known-malicious lists before they reach developers.
  4. Segment CI runners. Ephemeral, least-privilege build agents with no standing cloud credentials and egress filtering that blocks non-build destinations (WhatsApp infrastructure should never be reachable from a build runner).
  5. Monitor egress for developer endpoints. Add *.whatsapp.net / *.whatsapp.com connections from non-mobile processes to your alerting — legitimate WhatsApp usage in an enterprise is almost exclusively the desktop or mobile app, not Node.js.

There is no vendor patch or KEV deadline here — the remediation window is entirely self-imposed, which means organizations that defer it remain exposed indefinitely. Treat discovery of any PhantomSub package as a formal incident-response engagement, not a cleanup task.

Related Resources

Security Arsenal Penetration Testing Services AlertMonitor Platform Book a SOC Assessment vulnerability-management Intel Hub

Is your security operations ready?

Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.