LWA-2026-13341 confirmed malware

birch-css-utils@1.3.0

Malicious code in birch-css-utils (npm)

T1195.002 · Compromise Software Supply ChainT1059.007 · JavaScriptT1059 · Command and Scripting InterpreterT1027 · Obfuscated Files or InformationT1552.001 · Credentials In FilesT1552.005 · Cloud Instance Metadata APIT1082 · System Information DiscoveryT1071.001 · Web ProtocolsT1102 · Web ServiceT1105 · Ingress Tool TransferT1567 · Exfiltration Over Web ServiceT1041 · Exfiltration Over C2 Channel

Analysis

birch-css-utils@1.3.0 ships a vendored copy of tailwindcss 4.3.3 plus four obfuscated modules — cache-sweep.mjs, cache-warm.mjs, workspaces.js and build-cache.mjs — that act as a credential stealer and remote-command client. The modules hide their strings in base64 string tables XOR-decoded at runtime (atob + String.fromCharCode) and carry fake "Auto-generated by tailwindcss-theme-kit@0.2.0 – build cache manifest" headers. When imported, cache-sweep.mjs reads ~/.aws/credentials, ~/.aws/config and up to eight files from ~/.aws/sso/cache, collects environment variables matching a fixed prefix, walks up to five parent directories harvesting .env files, and fingerprints the host (hostname, platform, arch, node version, pid, cwd). The bundle is JSON-serialized, SHA-256 hashed and POSTed over HTTP(S) to a hardcoded host on port 443 with a fixed path, all stored as encoded strings. C2 state is cached in a JSON file written next to the module whose name is the first eight hex characters of sha256(cwd). If the primary endpoint fails twice and more than six hours have passed, the module falls back to a contract-resolved C2: it sends a JSON-RPC request to a hardcoded host on port 8543, reads result.transactions, filters `to` addresses matching a configured contract prefix, and decodes the real C2 host from address bytes 7-10 and the port from bytes 11-12. On a matching command it spawns a detached node process (detached:true, stdio ignored, windowsHide) with the payload passed in an environment variable. build-cache.mjs reads a JSON array from an environment variable, executes a fetched string with eval, and spawns detached node with the payload as an argument; cache-warm.mjs locates a parent package.json whose dependency name matches a fixed prefix and spawns detached node with NODE_OPTIONS pointing at a temp file. The package declares no install scripts, so the payload runs when the modules are imported rather than at install time.

analyzed by
Leitwacht
first seen
Oct 26, 2026, 12:20 AM
analyzed
Oct 26, 2026, 12:22 AM

Related advisories

browse all confirmed advisories →

Independently detected by the Leitwacht supply-chain probe. IOCs are defanged. Published CC0. Think this is a mistake? See the dispute policy.