Threat reportSupply ChainTL-2026-1805
Joyfill npm Supply-Chain Compromise: @joyfill/components and @joyfill/layouts Ship Obfuscated Worm-Like RAT and Credential Stealer
Joyfill npm Supply-Chain Compromise (TL-2026-1805), also tracked as Joyfill npm Compromise, is a critical-severity supply-chain compromise, first published 2026-07-28 and last reviewed 2026-08-13. It is attributed to WageMole (North Korea) with medium confidence, affects Joyfill @joyfill/components, maps to 34 MITRE ATT&CK techniques (T1005, T1027, T1036), and is covered by 9 detection rules and 48 indicators of compromise.
- Severity
- CRITICALAssessed severity
- CVEs
- 0None referenced
- Techniques
- 34MITRE ATT&CK
- Actors
- 3WageMole
- Detection rules
- 9SPL · KQL · Sigma
- IOCs
- 48Indicators of compromise
Key facts for TL-2026-1805
- Threat ID
- TL-2026-1805
- Also known as
- Joyfill npm Compromise, js.jadesnow campaign, JADESNOW npm vector
- Severity
- CRITICAL
- Status
- ACTIVE
- Category
- SUPPLY_CHAIN
- First published
- Last reviewed
- Attribution
- WageMole, Contagious Interview — DEV#POPPER, PolinRider loader family
- Attribution confidence
- MEDIUM
- Nation-state nexus
- North Korea
- Motivation
- FINANCIAL
- Target sectors
- software development, open source ecosystem, technology, cryptocurrency, devops ci-cd
- Target regions
- Global
- Detection rules
- 9
- Indicators of compromise
- 48
- Updates
- 2026-08-13 · 4 updates · revalidated 2×
Malware and tooling in Joyfill npm Supply-Chain Compromise
Malware and tooling: DEV#POPPER, JADESNOW, OmniStealer, EtherHiding, Socket.IO
How Joyfill npm Supply-Chain Compromise works
Malicious beta releases of @joyfill/components and @joyfill/layouts, published to npm on 2026-07-28, embed a five-stage obfuscated payload that resolves C2 addresses through Tron/BNB Smart Chain/Aptos blockchain transactions (an EtherHiding-style dead-drop resolver), opens a Socket.IO remote-access channel, stages a Python credential stealer, and achieves worm-like persistence by injecting a self-reloading loader into the global npm CLI, VS Code, Discord, and GitHub Desktop. Socket-based reporting links the loader family to the DEV#POPPER RAT and OmniStealer credential thief distributed by the North Korea-linked PolinRider supply-chain campaign (Contagious Interview / Famous Chollima), while Malpedia's initial classification (js.jadesnow) ties the blockchain-C2 technique to the separate UNC5342/WageMole DPRK cluster that pioneered EtherHiding.
On 2026-07-28, threat actors published malicious pre-release versions of two legitimate npm packages, @joyfill/components (4.0.0-rc24-2773-beta.4, -beta.5, -beta.6) and @joyfill/layouts (0.1.2-2773.beta.0, -beta.1, -beta.2), within hours of each other. The malicious code was injected exclusively into the compiled distribution bundles shipped in the published tarballs (dist/index.js, dist/index.esm.js, dist/joyfill.min.js for components; dist/index.cjs.js, dist/index.es.js for layouts) — the visible source repositories were untouched, indicating compromise of the registry publishing pipeline or a maintainer's publish credentials rather than a malicious pull request.
The payload's most consequential design choice is that it executes at package IMPORT time, not at npm install time. Because it never uses an npm lifecycle hook (no postinstall script), the widely-recommended defense `npm install --ignore-scripts` provides no protection whatsoever — any application that imports the compromised module triggers the chain the moment it loads.
Stage 1 is an obfuscated bootstrap loader that plants a campaign marker (`global["!"] = "9-0135-3"`), uses a seeded-PRNG string-shuffle decoder to alias core Node primitives under innocuous global names (`global.r = require`, `global.m = module`), and builds a Function-constructor ladder that never spells out the literal words "Function" or "eval" in cleartext to defeat static string-matching detections. A 30-second re-entry guard (`global._p_t`) prevents repeated execution during sandbox detonation, and the decoder function checksums its own source against a stored constant — any tampering (e.g., a debugger inserting breakpoints or a security tool patching the function) silently neuters execution instead of throwing, an anti-analysis pattern consistent with MITRE's Execution Guardrails: Environmental Keying (T1480.001).
Stage 2 resolves command-and-control infrastructure entirely through blockchain lookups rather than a hardcoded server, letting the operator rotate infrastructure at will while making takedown far harder — smart contracts and transactions on public chains are immutable and cannot be seized like a domain or IP. The resolver queries a fixed Tron address (TMfKQEd7TJJa5xNZJZ2Lep838vrzrs7mAP) for its latest outbound transaction; the `raw_data.data` field of that transaction contains a reversed BNB Smart Chain transaction hash. The loader then calls `eth_getTransactionByHash` against a BSC RPC endpoint, and the returned transaction's input field holds an XOR-encrypted payload that is decrypted with a repeating-key cipher. If this path fails, the loader falls back to an Aptos account as a secondary dead-drop pointer. This exact technique — using blockchain read calls as a censorship-resistant C2 dead-drop resolver — is known as EtherHiding, first documented by Google Threat Intelligence Group/Mandiant in October 2025 against the DPRK-linked UNC5342 (aka WageMole/Famous Chollima/Nickel Tapestry/Storm-1877/Void Dokkaebi/WaterPlum/PurpleBravo) cluster's JADESNOW downloader. The resolver runs on two parallel branches — an in-process branch using direct `eval()` and a detached child process — each with its own XOR key and blockchain pointer set, and the detached branch separately queries 23.27.13.43 for a secondary payload.
A campaign-tag variable (`_V`, rendered as HTTP header `Sec-V: A9-0135-3` for the npm infection vector) selects the live C2 endpoint: the npm campaign resolves Socket.IO and upload traffic to 166.88.134.62 (ports 80/443), while other campaign variants of the same loader point to 198.105.127.210 and 23.27.202.27.
Stage 3 is a roughly 77 KB Socket.IO-based RAT (LZString-compressed string table, 337 entries) that fingerprints the host — detecting CI/sandbox environments via hostname markers (`github-runner`, `buildbot`, `sandbox-pool-`, `buildkitsandbox`, `cloudchamber`, WSL2, running as `root`) — and self-heals its own dependency by running `npm install socket.io-client` at runtime if the module is missing. Supported remote commands include `ss_info` (full host/campaign/UUID report), `ss_ip` (geolocation via the legitimate ip-api.com service), `ss_cb` (clipboard theft via PowerShell/pbpaste/xclip-xsel), `ss_upf`/`ss_upd` (file/directory exfiltration via multipart POST to `/u/f`), `ss_eval:`/`ss_eval64:` (arbitrary JavaScript execution, plaintext or base64), `ss_inz:`/`ss_inzx:` (loader injection into other local applications — the worm-propagation primitive), `ss_connect:` (C2 redirection), and `~py` (staging of the Python credential stealer as a detached process).
Stage 4, the Python credential stealer, targets developer workstations directly: browser-stored passwords and cryptocurrency-wallet browser extensions, Git and GitHub CLI credentials/tokens, npm publish tokens, and OS keychains. Stolen data is packed into an encrypted archive staged at `%USERPROFILE%\.npm` (Windows) or `/tmp/.npm` (Linux/macOS) before upload to the C2. Socket-based analysis assesses this stealer with medium confidence as a variant of OmniStealer, a Python infostealer previously documented targeting cryptocurrency wallet private keys, browser session cookies, Git credentials, and cloud API tokens on developer machines.
Stage 5 achieves persistence and self-propagation by injecting self-reloading code blocks — guarded by comment sentinels (`/*C250617A*/`, `/*C250618A*/`, `/*C250619A*/`, `/*C260511A*/`, `/*C260512A*/`, `/*RS260605*/`) that prevent re-injection — into `@vscode/deviceid` (affecting VS Code, Cursor, and Antigravity), the Discord desktop core module, GitHub Desktop's `main.js`, and critically the globally installed npm CLI at `<npm root -g>/npm/lib/cli.js`. Once the global CLI is infected, every subsequent `npm` invocation on that machine re-executes the loader, and any package later built or published from that machine can carry the infection forward — closing a worm-like propagation loop across the npm ecosystem.
Attribution carries two overlapping but distinct hypotheses, both pointing to North Korea. Socket researchers matched the Stage 3 loader's code patterns to the PolinRider loader family and linked the final payload to the DEV#POPPER RAT family, explicitly noting their findings are "based on technical similarities and published research rather than attributing the compromise to a specific threat actor." PolinRider is an active, larger supply-chain campaign (ongoing since December 2025; 108 malicious packages/extensions across npm, Go, Packagist, and a Chrome extension; 162 release artifacts; 1,951 compromised public GitHub repositories across 1,047 owners as of 2026-04-11) attributed to North Korea's Contagious Interview / Famous Chollima cluster, which recruits developers via fake job interviews and poisoned coding-assessment repositories to deliver DEV#POPPER and OmniStealer. Separately, Malpedia's initial classification filed the delivered RAT under the js.jadesnow malware family, an alias of the JADESNOW downloader associated with UNC5342/WageMole — a related but distinct DPRK cluster credited with pioneering the EtherHiding blockchain-C2 technique this payload's Stage 2 resolver reuses. Both attributions converge on financially-motivated, state-linked North Korean operations that fund the regime through developer-targeted credential and cryptocurrency theft; this research documents both hypotheses rather than forcing a single unverified conclusion.
No CVE applies — this is a malicious publication to the npm registry, not a vulnerability in the legitimate Joyfill codebase. Remediation is therefore centered on version rollback, credential rotation, and injection-marker scanning rather than patching.
MITRE ATT&CK techniques used in TL-2026-1805
Collection
T1005 Data from Local System; T1074 Data Staged; T1115 Clipboard Data; T1560 Archive Collected Data
Defense Evasion
T1027 Obfuscated Files or Information; T1036 Masquerading; T1140 Deobfuscate/Decode Files or Information; T1480 Execution Guardrails; T1497 Virtualization/Sandbox Evasion; T1620 Reflective Code Loading
Exfiltration
T1041 Exfiltration Over C2 Channel
Discovery
T1057 Process Discovery; T1082 System Information Discovery; T1083 File and Directory Discovery; T1087 Account Discovery; T1518 Software Discovery; T1614 System Location Discovery
Execution
T1059 Command and Scripting Interpreter; T1129 Shared Modules
Command and Control
T1071 Application Layer Protocol; T1102 Web Service; T1105 Ingress Tool Transfer; T1573 Encrypted Channel
Lateral Movement
T1072 Software Deployment Tools; T1080 Taint Shared Content
Initial Access
Credential Access
T1528 Steal Application Access Token; T1539 Steal Web Session Cookie; T1552 Unsecured Credentials; T1555 Credentials from Password Stores
Persistence
T1554 Compromise Host Software Binary
Resource Development
T1583 Acquire Infrastructure; T1587 Develop Capabilities; T1608 Stage Capabilities
Affected products and versions in Joyfill npm Supply-Chain Compromise
- Joyfill — @joyfill/components
Vulnerable versions: 4.0.0-rc24-2773-beta.4; 4.0.0-rc24-2773-beta.5; 4.0.0-rc24-2773-beta.6
Fixed in: 4.0.0-rc24 (pre-compromise pinned release) - Joyfill — @joyfill/layouts
Vulnerable versions: 0.1.2-2773.beta.0; 0.1.2-2773.beta.1; 0.1.2-2773.beta.2
Fixed in: 0.1.1 (pre-compromise pinned release)
Remediation for Joyfill npm Supply-Chain Compromise
Patches
- No CVE or vendor patch applies; the legitimate Joyfill codebase itself contains no defect — remediation is version rollback/removal of the malicious publications, not patching.
Immediate actions
- Remove @joyfill/components versions 4.0.0-rc24-2773-beta.4, -beta.5, -beta.6 and @joyfill/layouts versions 0.1.2-2773.beta.0, -beta.1, -beta.2 from all package.json files, lockfiles, internal registries/mirrors, and build/CI images.
- Grep all lockfiles for the '2773' pre-release marker: `grep -rEn 'joyfill.*2773' package-lock.json yarn.lock pnpm-lock.yaml`.
- Delete node_modules and reinstall from a clean, pinned lockfile using known-good releases (e.g. @joyfill/components@4.0.0-rc24, @joyfill/layouts@0.1.1 or a later verified fixed release).
- Inspect the global npm CLI (`<npm root -g>/npm/lib/cli.js`), `@vscode/deviceid`, the Discord desktop core module, and GitHub Desktop's `main.js` for the injection-marker comments (/*C250617A*/, /*C250618A*/, /*C250619A*/, /*C260511A*/, /*C260512A*/, /*RS260605*/) and reinstall or reimage any application where a marker is found.
Workarounds
- Pin dependency resolution to pre-2026-07-28 published versions and block installation of any '2773' pre-release tag via registry policy (npm package allowlisting or a private registry proxy).
Longer-term hardening
- Rotate all credentials present on any machine that imported the compromised packages: browser-stored passwords and extension wallet keys, Git/GitHub CLI tokens, npm publish tokens, cloud API tokens, and OS keychain secrets.
- Deploy egress monitoring/allowlisting (e.g. GitHub Actions Harden-Runner) to flag anomalous outbound connections from Node.js/CI processes to blockchain RPC endpoints (Tron, BNB Smart Chain, Aptos) and to the identified C2 IPs during install/build/test phases.
- Adopt npm provenance/Sigstore attestation verification and pin dependencies to hash-verified releases to reduce exposure to pre-release/beta-channel poisoning.
- Train developers on Contagious Interview / Famous Chollima social-engineering vectors (fake recruiter outreach, poisoned coding-assessment repositories), given this payload's links to the broader PolinRider campaign.
Weaknesses (CWE) in Joyfill npm Supply-Chain Compromise
Timeline of Joyfill npm Supply-Chain Compromise
- Google Threat Intelligence Group / Mandiant publishes the first documented nation-state use of EtherHiding (blockchain smart-contract C2) by DPRK-linked UNC5342/WageMole activity — the same dead-drop-resolver technique reused in this payload's Stage 2 blockchain C2 resolver.
- The PolinRider supply-chain campaign, attributed to North Korea's Contagious Interview / Famous Chollima cluster, begins compromising open-source package maintainers via poisoned GitHub repositories to deliver the DEV#POPPER RAT and OmniStealer credential thief.
- PolinRider's reach is documented at 108 malicious packages/extensions (162 release artifacts) across npm, Go, Packagist, and a Chrome extension, having compromised 1,951 public GitHub repositories across 1,047 unique owners.
- The malicious beta versions are unpublished from the npm registry within hours of detection, though cached copies persist on registry mirrors.
- StepSecurity detonates all six malicious versions in a Harden-Runner sandbox (confirming no install-time scripts or child processes, consistent with import-time execution) and binary-diffs the bundles against clean sibling releases, isolating ~333 lines of injected code.
- StepSecurity's OSS AI scanning engine automatically flags @joyfill/layouts@0.1.2-2773.beta.0 as CRITICAL with a security score of 0/10 and a REJECTED verdict.
- Analysts observe that the C2 servers and blockchain resolver pointer addresses were already offline or re-armed within hours of the compromise being disclosed.
- Malpedia creates a library entry classifying the delivered payload under the js.jadesnow malware family, tying it to the JADESNOW/EtherHiding lineage.
- StepSecurity researcher Varun Sharma publishes technical analysis of the compromise, documenting the import-time execution mechanism, global npm CLI injection, and the blockchain-based C2 resolver.
- Malicious pre-release versions of @joyfill/components (beta.4, beta.5, beta.6) and @joyfill/layouts (beta.0, beta.1, beta.2) are published to the npm registry within hours of each other, with the payload injected only into compiled distribution bundles.
- The Hacker News, GBHackers, CyberSecurityNews, CyberPress, and The Cyber Express republish and expand the technical analysis; Socket researchers link the payload's loader code patterns to the DEV#POPPER/PolinRider family based on technical similarity, without formally attributing the compromise to a specific actor.
- Archive.org captures a snapshot of the StepSecurity report for preservation.
- Vendor and community guidance converges on version rollback/pinning, developer credential rotation, and scanning for the Stage 5 injection-marker comments across the global npm CLI, VS Code, Discord, and GitHub Desktop.
Update history for TL-2026-1805
- 2026-08-13 — tweetfeed.live community intel: New TL_OSINT_Scan community intel: 1 newly-corroborated indicator(s), 64 community-related indicator(s).
- 2026-08-04 — tweetfeed.live community intel: New TL_OSINT_Scan community intel: 1 newly-corroborated indicator(s), 65 community-related indicator(s).
- 2026-08-02 — Joyfill npm Supply-Chain Attack: Import-Time DEV#POPPER RAT and OmniStealer Credential Stealer in @joyfill/components and @joyfill/layouts: What changed No severity/exploitability/status escalation — both reports agree CRITICAL / ACTIVE / ACTIVE with MEDIUM attribution confidence. This is an intelligence-refinement pass, not an escalation. New indicators (6) 2 previously-redact
- 2026-08-02 — Hijacked Joyfill npm Packages (@joyfill/components, @joyfill/layouts) Deploy DEV#POPPER-Family Worm-Like Socket.IO RAT and Python Credential Stealer: What changed No change to severity/exploitability/status (still CRITICAL/ACTIVE/ACTIVE). The newer reporting adds technical granularity: two additional payload-stage SHA256 hashes, a Python-stealer exfil endpoint, specific developer-tool in
Sources cited for Joyfill npm Supply-Chain Compromise
- Compromised npm Packages: @joyfill/components and @joyfill/layouts Ship an Obfuscated Remote Access Trojan
- Malpedia library entry: js.jadesnow (Joyfill incident)
- JADESNOW (Malware Family) — Malpedia
- Two Compromised joyfill npm Packages Run RAT When Imported Into Node.js
- Joyfill npm Credential Stealer Targets GitHub Tokens, Browser Passwords and Crypto Wallets
- Joyfill npm Supply-Chain Attack Deploys RAT and Developer Credential Stealer
- Joyfill Npm Packages Hit By DEV#POPPER Node.js Malware
- North Korean threat actors turn blockchains into malware delivery servers
- PolinRider: North Korea-Linked Supply Chain Campaign Expands Across Open Source Ecosystems
Detection coverage for TL-2026-1805
As of 2026-08-13, Threadlinqs Intelligence publishes 9 detection rule(s) for TL-2026-1805 across Splunk SPL, Microsoft KQL and Sigma, covering 48 indicator(s) of compromise. The whole corpus is readable without an account; a free account unlocks full detection query text in Splunk SPL, Microsoft KQL and Sigma; paid tiers add raw indicator values, correlation and the MCP server. Threadlinqs MCP server · View plans.
Community OSINT corroboration for TL-2026-1805
2 of this threat's indicators have also been reported by the open-source security community, which observed at least one of them before this report was published. Community sightings are unverified and are kept separate from Threadlinqs' curated indicators. Indicator values, reporters and campaign linkage are available to authenticated Red-tier users.