
Socket: Two Joyfill npm Beta Releases Compromised to Deliver DEV#POPPER Remote Access Trojan
Socket's research team found two beta releases of the @joyfill npm packages (@joyfill/layouts and @joyfill/components) contained an import-time JavaScript implant that resolves encrypted payloads through Tron, Aptos, and BNB Smart Chain transactions, ultimately dropping a 77KB Node.js remote-access trojan matching the DEV#POPPER family and sharing loader fingerprints with the PolinRider blockchain-loader campaign. The RAT establishes a Socket.IO C2 channel, executes arbitrary JS/shell commands, exfiltrates files and clipboard data, and persists by patching files inside VS Code, Cursor, Antigravity, Discord Desktop, GitHub Desktop, and the global npm CLI; a parallel detached-process branch fetches an additional bootstrap that can deploy a Python credential/browser-data stealer assessed as an OmniStealer variant. Because the implant fires on module load (not via npm lifecycle scripts), `--ignore-scripts` provides no protection, and the writeup includes full IOCs, blockchain addresses, C2 infrastructure, and MITRE ATT&CK mappings.
What it is
Concrete version boundaries and response actions for the compromised @joyfill npm beta releases the summary describes. The affected artifacts are exactly @joyfill/layouts@0.1.2-2773.beta.0 (published 2026-07-28T10:54:57Z) and @joyfill/components@4.0.0-rc24-2773-beta.4 (published ~9 minutes later by the same npm identity, Node 18.20.0/npm 10.5.0, both carrying the 2773 prerelease marker). The immediately preceding @joyfill/layouts@0.1.1 and @joyfill/components@4.0.0-rc24 are clean, as are other public @joyfill packages checked. Each package sees ~16,000 weekly downloads, but these overlap (components depends on layouts) and don't reflect beta-tag installs.
Preconditions / Affected
Only @joyfill/layouts@0.1.2-2773.beta.0 executes the implant reliably: it fires when Node loads the CommonJS entrypoint. The components beta contains the same source-level injection in dist/index.js, dist/index.esm.js, and dist/joyfill.min.js, but its Rollup bundle ships a throwing dynamic-require shim that prevents the loader resolving network dependencies in the normal bundled path — Socket assesses this limits execution in that artifact without making it safe. The source maps attribute the implant to src/utils/reactGridLayoutUtils.js, proving it was present at bundle time (maintainer/build compromise), not injected into a final tarball.
What to do
- Pin to verified clean versions and block restoration of the bad ones:
@joyfill/layouts@0.1.1@joyfill/components@4.0.0-rc24- Avoid the beta dist-tag for these packages until Joyfill confirms remediation. Purge both bad versions from lockfiles, caches, internal mirrors, build images, and deployment artifacts.
- Do not rely on
npm install --ignore-scripts— no lifecycle hook is used; import triggers it. - Treat any host that imported the layouts beta as compromised (interactive remote shell), not merely at risk of theft. Isolate, preserve logs/dependency artifacts, and rotate reachable credentials from a separate uncompromised machine, before other steps.
Detection signals the page calls high-value:
- Blockchain RPC egress from a CI runner or dev workstation —
api[.]trongrid[.]io,bsc-dataseed[.]binance[.]org,fullnode[.]mainnet[.]aptoslabs[.]com,bsc-rpc[.]publicnode[.]com— is "high-fidelity on its own." - Detached Node.js processes; the
Sec-Vheader; the four C2 IPs (166[.]88[.]134[.]62,198[.]105[.]127[.]210,23[.]27[.]13[.]43,23[.]27[.]202[.]27:27017). - Persistence injections (search for these tags) in
@vscode/deviceid(VS Code, Cursor, Antigravity), Discord Desktop's core module, GitHub Desktopresources/app/main.js, and global npm CLI (npm root -g,node_modules/npm/lib/cli.js):/*C250617A*/,/*C250618A*/,/*C250619A*/,/*C250620A*/,/*C260511A*/,/*C260512A*/,/*RS260605*/. - If the Python follow-on ran: check staging dirs
%USERPROFILE%\.npmor/tmp/.npm, and rotate browser-saved passwords/cookies and wallet/password-manager extension data — not just developer-tool creds.
The RAT avoids execution on hostnames including github-runner, buildbot, buildkitsandbox, and microsoft-standard-WSL2, so a clean sandbox may not reproduce it.
Caveats
The DEV#POPPER and PolinRider labels are family assessments from direct code overlap, not attribution to a group. The /$/boot and Python-stealer captures were pulled once from a disposable VM with no request provenance tying them to a specific infected Joyfill host — they're treated as matching downstream samples, and the OmniStealer identification is medium-likelihood. Source maps confirm bundle-time presence but don't identify the initial access vector (workstation, repo, CI, or publishing credential).
Organisations named here
- eSentire
- T1115
Technologies named here
- @joyfill/layouts
- Socket.IO
- axios
- @joyfill/components
- pyzipper
- Telegram
- @vscode/deviceid
- PowerShell / pbpaste / xclip / xsel
- ip-api.com
- Discord Desktop
- GitHub Desktop
- npm CLI
- npm
- Node.js
- Python
- JavaScript
- Joyfill
Techniques named here
- Compromise Software Supply Chain
- Obfuscated Files or Information
- Encrypted or Encoded File
- JavaScript
- Unix Shell
- Web Protocols
- Ingress Tool Transfer
- Clipboard Data
Threat actors named here
- PolinRider
- DEV#POPPER
- OmniStealer
- ShoeVista
Also named here
- T1195.002
- T1027
- T1027.013
- T1059.007
- T1059.006
- T1059.004
- T1071.001
- T1105
Related in Supply Chain


