Back to Intelligence

MALFEX npm Supply Chain Campaign: Detecting and Removing the Overlord RAT and Info-Stealer in Your Developer Environment

SA
Security Arsenal Team
October 7, 2026
11 min read

CloudSEK and Checkmarx have jointly disclosed a long-running npm supply chain campaign, codenamed MALFEX, that has been quietly poisoning the JavaScript ecosystem since August 2023. The activity is attributed to a lone threat actor who published 12 packages to the npm registry — eight of which are confirmed malicious and collectively racked up 40,767 downloads before disclosure. The payload is a one-two punch: an information stealer that harvests credentials, browser data, and environment secrets, followed by the Overlord RAT, which gives the operator persistent remote access to compromised hosts.

This is not a theoretical risk. Every one of those downloads represents a developer workstation, a build agent, or a CI/CD runner that executed attacker-controlled code. If your organization builds JavaScript or TypeScript applications — and statistically, it does — you need to assume developer endpoints are in scope and hunt accordingly. Supply chain compromises like MALFEX bypass traditional perimeter controls entirely because the malware arrives via a trusted channel: your own dependency resolution.

Technical Analysis

Affected Ecosystem and Delivery Mechanism

  • Registry: npm (Node.js package registry)
  • Campaign: MALFEX (CloudSEK / Checkmarx designation)
  • Packages: 12 published by a single actor since August 2023; 8 confirmed malicious
  • Download volume: 40,767 across the eight malicious packages
  • Payloads: Information stealer + Overlord RAT (remote access trojan)

No CVE is assigned to this campaign — that is typical for malicious package operations. These are not vulnerabilities in npm itself; they are deliberately weaponized packages that abuse the trust model of open-source registries.

How the Attack Works

MALFEX follows the playbook that has become standard for npm ecosystem attacks, and defenders should understand each stage:

  1. Package publication and social engineering. The actor published packages with names designed to be typosquatted or mistaken for legitimate utilities. Some packages masquerade as helpful tooling to drive organic installs beyond typos.
  2. Install-time execution. The malicious logic is typically wired into npm lifecycle hooks — preinstall, install, or postinstall scripts in package.json. This means the payload executes the moment a developer or CI pipeline runs npm install, before a single line of the package's actual code is imported. Alternatively, obfuscated JavaScript in the package entry point detonates on first require()/import.
  3. Staging. The initial loader is heavily obfuscated (base64 blobs, string-array rotation, eval()/Function() constructors) and pulls second-stage payloads from attacker-controlled infrastructure, often hosted on paste sites, Discord CDNs, or disposable domains.
  4. Credential theft. The stealer component targets browser credential stores (Chrome/Edge/Firefox login data and cookies), cryptocurrency wallets, SSH keys (~/.ssh/), cloud credentials (~/.aws/credentials, ~/.azure/), and critically — environment variables, which on CI runners expose tokens for npm itself, GitHub, cloud providers, and artifact registries.
  5. RAT deployment and persistence. Overlord RAT establishes command-and-control, giving the actor hands-on-keyboard access: arbitrary command execution, file exfiltration, and lateral movement capability. On Windows, persistence is typically established via registry Run keys or scheduled tasks; on Linux/macOS via shell profile modification or cron.

Why This Is Dangerous Beyond the Endpoint

The real blast radius of an npm supply chain compromise is downstream. A developer machine with Overlord RAT installed is a foothold into source code repositories, signing keys, and internal registries. A compromised CI runner means the attacker can poison your build artifacts — turning a single malicious dependency into a supply chain attack against your own customers. This is the SolarWinds/CodeCov lesson replaying at package scale.

Exploitation Status

Confirmed active and in-the-wild. 40,767 downloads over the campaign's lifespan means tens of thousands of potential execution events. The packages have been reported to npm, but downloads already occurred and any host that installed these packages should be treated as potentially compromised, not merely "exposed."

Detection & Response

The most reliable detection surface for MALFEX-class threats is process lineage: node.exe or npm/cmd install hooks spawning scripting engines, network tools, or credential-access utilities is almost never legitimate on developer endpoints or build agents. The rules below are tuned for that signal.

SIGMA Rules

YAML
---
title: NPM Install Hook Spawning Scripting or Shell Child Process
id: 3f8a1c42-7b2d-4e19-a5c6-9d0e1f2a3b4c
status: experimental
description: Detects node.exe or npm lifecycle hooks spawning cmd, powershell, curl, or other child processes — consistent with malicious npm packages such as the MALFEX campaign executing postinstall payloads.
references:
  - https://thehackernews.com/2026/10/eight-malicious-npm-packages-downloaded.html
  - https://attack.mitre.org/techniques/T1195/002/
author: Security Arsenal
date: 2026/10/15
tags:
  - attack.initial_access
  - attack.t1195.002
  - attack.execution
logsource:
  category: process_creation
  product: windows
detection:
  selection_parent:
    ParentImage|endswith:
      - '\node.exe'
      - '\npm.cmd'
      - '\cmd.exe'
  selection_parent_cmdline:
    ParentCommandLine|contains:
      - 'npm install'
      - 'npm ci'
      - 'postinstall'
      - 'preinstall'
  selection_child:
    Image|endswith:
      - '\powershell.exe'
      - '\pwsh.exe'
      - '\cmd.exe'
      - '\curl.exe'
      - '\certutil.exe'
      - '\wscript.exe'
      - '\cscript.exe'
      - '\mshta.exe'
      - '\bitsadmin.exe'
  condition: selection_parent and selection_parent_cmdline and selection_child
falsepositives:
  - Legitimate build tooling (node-gyp, node-pre-gyp) compiles native modules during install; baseline known-good packages in your environment
level: high
---
title: Node Process Accessing Browser Credential Stores
id: 8c4d2e51-3a6f-4b78-9c1d-2e5f6a7b8c9d
status: experimental
description: Detects node.exe reading browser Login Data or Cookies files — a hallmark of npm-delivered info-stealers such as the MALFEX campaign payload.
references:
  - https://thehackernews.com/2026/10/eight-malicious-npm-packages-downloaded.html
  - https://attack.mitre.org/techniques/T1555/003/
author: Security Arsenal
date: 2026/10/15
tags:
  - attack.credential_access
  - attack.t1555.003
logsource:
  category: file_event
  product: windows
detection:
  selection_image:
    Image|endswith: '\node.exe'
  selection_target:
    TargetFilename|contains:
      - '\Google\Chrome\User Data\'
      - '\Microsoft\Edge\User Data\'
      - '\BraveSoftware\Brave-Browser\User Data\'
      - '\Mozilla\Firefox\Profiles\'
  selection_file:
    TargetFilename|endswith:
      - 'Login Data'
      - 'Cookies'
      - 'Web Data'
      - 'logins.json'
      - 'key4.db'
  condition: selection_image and selection_target and selection_file
falsepositives:
  - Rare; legitimate Electron apps may touch their own profile data but not other browsers' stores
level: critical
---
title: Node Process Establishing Outbound Connection to Paste or Chat CDN Infrastructure
id: 5e2b7a93-1d4c-4f08-b3a7-6c9d0e1f2a3b
status: experimental
description: Detects node.exe making outbound connections to paste sites or Discord CDN/webhook endpoints commonly abused for payload staging and exfiltration by npm supply chain malware including MALFEX.
references:
  - https://thehackernews.com/2026/10/eight-malicious-npm-packages-downloaded.html
  - https://attack.mitre.org/techniques/T1102/
author: Security Arsenal
date: 2026/10/15
tags:
  - attack.command_and_control
  - attack.t1102
  - attack.exfiltration
logsource:
  category: network_connection
  product: windows
detection:
  selection:
    Image|endswith:
      - '\node.exe'
      - '\npm.cmd'
    DestinationHostname|contains:
      - 'pastebin.com'
      - 'paste.ee'
      - 'rentry.co'
      - 'discord.com'
      - 'discordapp.com'
      - 'cdn.discordapp.com'
      - 'transfer.sh'
      - 'file.io'
  condition: selection
falsepositives:
  - Some legitimate dev tools integrate with Discord webhooks for notifications; verify against package inventory
level: high

KQL — Microsoft Sentinel / Defender

KQL — Microsoft Sentinel / Defender
// Hunt for npm/node install activity spawning suspicious child processes (MALFEX TTP)
// Works on DeviceProcessEvents (Defender) — extend join to DeviceNetworkEvents for C2 staging
let Lookback = 14d;
DeviceProcessEvents
| where Timestamp > ago(Lookback)
| where InitiatingProcessFileName in~ ("node.exe", "npm.cmd", "cmd.exe")
| where InitiatingProcessCommandLine has_any ("npm install", "npm ci", "postinstall", "preinstall")
| where FileName in~ ("powershell.exe", "pwsh.exe", "cmd.exe", "curl.exe", "certutil.exe",
                      "wscript.exe", "cscript.exe", "mshta.exe", "bitsadmin.exe", "rundll32.exe")
| extend SuspiciousCommand = ProcessCommandLine
| project Timestamp, DeviceName, AccountName,
          ParentCmd = InitiatingProcessCommandLine,
          ChildProcess = FileName, SuspiciousCommand,
          SHA256, FolderPath
| join kind=leftouter (
    DeviceNetworkEvents
    | where Timestamp > ago(Lookback)
    | where InitiatingProcessFileName in~ ("node.exe", "powershell.exe", "cmd.exe")
    | where RemoteUrl has_any ("pastebin", "discord", "rentry", "transfer.sh", "file.io")
       or RemoteIpType == "Public"
    | project Timestamp, DeviceName, InitiatingProcessFileName, RemoteUrl, RemoteIP, RemotePort
) on DeviceName, $left.FileName == $right.InitiatingProcessFileName
| project Timestamp, DeviceName, AccountName, ParentCmd, ChildProcess, SuspiciousCommand,
          RemoteUrl, RemoteIP, SHA256
| order by Timestamp desc;

For environments ingesting Sysmon or endpoint telemetry via CEF/Syslog into Sentinel, the same hunt translates to SecurityEvent/Syslog by filtering on process lineage (ParentProcessName containing node and Process in the suspicious child list).

Velociraptor VQL

VQL — Velociraptor
-- MALFEX npm Supply Chain Triage: malicious node child processes, persistence, and credential-store access
-- Deploy as a hunt across developer workstations and build agents

SELECT Pid, Ppid, Name, CommandLine, Exe, Username, CreateTime
FROM pslist()
WHERE (
  -- node/npm spawning shells, downloaders, or script engines
  (CommandLine =~ '(?i)npm (install|ci)|postinstall|preinstall'
    AND Name =~ '(?i)(powershell|pwsh|cmd|curl|certutil|wscript|cscript|mshta|bash|sh)')
  -- node itself executing encoded or download-cradle style commands
  OR (Name =~ '(?i)node' AND CommandLine =~ '(?i)frombase64string|-enc |iex|invoke-expression|downloadstring')
)

-- Companion check: registry Run key persistence referencing node or unknown binaries in user paths
-- SELECT Name, Data FROM glob(globs='HKEY_USERS/*/Software/Microsoft/Windows/CurrentVersion/Run/*',
--        accessor='registry')
-- WHERE Data =~ '(?i)node|appdata|temp'

Remediation and Verification Script

Use this PowerShell script to triage Windows developer workstations and build agents for MALFEX-style compromise: it enumerates globally installed npm packages, flags suspicious lifecycle scripts in installed dependencies, checks persistence locations, and identifies node processes with unusual network activity.

PowerShell
# MALFEX npm Supply Chain Triage - Security Arsenal
# Run elevated on developer workstations and CI/CD build agents

Write-Host "=== [1/5] Installed npm global packages ===" -ForegroundColor Cyan
npm ls -g --depth=0 2>$null

Write-Host "=== [2/5] Scanning node_modules for suspicious lifecycle hooks ===" -ForegroundColor Cyan
$searchPaths = @("$env:USERPROFILE", "C:\builds", "C:\agent\_work")
foreach ($base in $searchPaths) {
    if (Test-Path $base) {
        Get-ChildItem -Path $base -Recurse -Filter "package.json" -ErrorAction SilentlyContinue |
          Where-Object { $_.FullName -match 'node_modules' } |
          ForEach-Object {
            $pkg = Get-Content $_.FullName -Raw | ConvertFrom-Json -ErrorAction SilentlyContinue
            if ($pkg.scripts -and ($pkg.scripts.preinstall -or $pkg.scripts.install -or $pkg.scripts.postinstall)) {
                $hook = "$($pkg.scripts.preinstall) $($pkg.scripts.install) $($pkg.scripts.postinstall)"
                if ($hook -match '(?i)curl|wget|powershell|invoke|eval|base64|http') {
                    Write-Warning "Suspicious install hook: $($_.FullName)`n  -> $hook"
                }
            }
          }
    }
}

Write-Host "=== [3/5] Checking persistence (Run keys / Scheduled Tasks referencing node or user-writable paths) ===" -ForegroundColor Cyan
Get-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run",
                 "HKLM:\Software\Microsoft\Windows\CurrentVersion\Run" -ErrorAction SilentlyContinue |
  Out-String | Select-String -Pattern '(?i)node|appdata|temp' | ForEach-Object { Write-Warning $_.Line }
Get-ScheduledTask | Where-Object { $_.Actions.Execute -match '(?i)node|powershell' -and
  $_.Actions.Arguments -match '(?i)appdata|temp|-enc' } |
  ForEach-Object { Write-Warning "Suspicious task: $($_.TaskName) -> $($_.Actions.Execute) $($_.Actions.Arguments)" }

Write-Host "=== [4/5] Node processes with active outbound connections ===" -ForegroundColor Cyan
Get-NetTCPConnection -State Established -ErrorAction SilentlyContinue |
  Where-Object { (Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).ProcessName -match 'node' } |
  Where-Object { $_.RemoteAddress -notmatch '^(127\.|10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.)' } |
  Select-Object LocalPort, RemoteAddress, RemotePort, OwningProcess,
    @{N='Process';E={(Get-Process -Id $_.OwningProcess).ProcessName}} | Format-Table -AutoSize

Write-Host "=== [5/5] Browser credential-store access check (recent prefetch/amcache not covered - manual DFIR if hits above) ===" -ForegroundColor Cyan
Write-Host "If any warnings fired above: isolate host, rotate ALL credentials reachable from it (npm tokens, SSH keys, cloud creds, browser passwords), and reimage if Overlord RAT activity is confirmed." -ForegroundColor Yellow

Remediation

MALFEX has no patch because it is not a vulnerability — remediation means removal, rotation, and hardening of the dependency pipeline itself.

Immediate actions (do these today):

  1. Identify exposure. Pull your package inventory: search lockfiles (package-lock.json, yarn.lock, pnpm-lock.yaml) across all repositories for the malicious package names published in the CloudSEK and Checkmarx reports. Check npm audit logs and artifact proxy (Artifactory/Nexus/Verdaccio) download logs for historical installs going back to August 2023.
  2. Treat installs as compromises. Any host that executed npm install against a malicious package ran attacker code. Isolate the host, capture forensic images, and hunt for Overlord RAT persistence (Run keys, scheduled tasks, cron entries, shell profile modifications) before wiping.
  3. Rotate everything the host could reach. npm tokens, GitHub/GitLab PATs, SSH keys, cloud provider credentials (~/.aws, ~/.azure, ~/.gcloud), browser-stored passwords, and any secrets in environment variables on CI runners. Assume the stealer exfiltrated all of it — because that is exactly what it was built to do.
  4. Rebuild affected artifacts. If a compromised build agent produced released artifacts, treat those artifacts as suspect and rebuild from a clean pipeline. Check whether any internal packages were published during the exposure window.

Structural hardening (this quarter):

  • Disable lifecycle scripts by default. Set ignore-scripts=true in .npmrc for CI pipelines and developer environments, and explicitly allowlist the small set of packages (node-gyp dependents) that legitimately need install scripts. This single control would have neutered the MALFEX install-hook vector.
  • Pin and gate dependencies. Enforce lockfile integrity in CI, use npm ci instead of npm install in pipelines, and route all registry traffic through an internal proxy with malware scanning and a quarantine policy for newly published packages (e.g., block packages younger than 7–14 days unless allowlisted).
  • Deploy SCA with malicious-package intelligence. Ensure your software composition analysis tooling consumes malicious-package feeds (Checkmarx, Socket, GitHub Advisory Database) — not just CVE data — because campaigns like MALFEX will never have a CVE.
  • Segment CI/CD. Build agents should be ephemeral, minimally permissioned, and unable to reach production signing keys or deploy credentials except through short-lived, scoped tokens. A compromised build should cost you a build, not your release pipeline.
  • Monitor egress from developer and build subnets. node.exe making connections to paste sites, Discord CDNs, or newly registered domains should alert. Most developer machines have no legitimate reason to talk to Pastebin mid-build.

The broader lesson: npm's trust model is the attack surface. A lone actor kept a malicious package operation alive for over two years and accumulated 40,000+ downloads because the ecosystem optimizes for convenience over verification. Until your pipeline verifies what it installs, you are one typo away from running the next Overlord RAT on a machine with production credentials.

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.