Compromised Joyfill npm Beta Releases Deliver DEV#POPPER RAT

Summary
Socket researchers found import-time malware in two Joyfill npm beta releases. The implant retrieves payloads through blockchain transactions and can deliver a remote-access trojan; separate captured payloads include a credential-stealing Python program.
Key points
- Affected versions are @joyfill/layouts@0.1.2-2773.beta.0 and @joyfill/components@4.0.0-rc24-2773-beta.4.
- The layouts implant runs when the package is imported, not during installation, so npm install --ignore-scripts does not prevent execution.
- The loader resolves payloads through Tron, Aptos, and BNB Smart Chain data, and starts a separate detached Node.js process that requests /$/boot.
- The recovered 77 KB DEV#POPPER RAT supports remote command execution, file uploads, clipboard collection, and persistence in developer tools.
- Separately captured downstream samples include a Python infostealer targeting browser data, credentials, and developer tools; the captures were not tied to a specific infected Joyfill host.
- The initial access method is unknown. Source maps show the implant was present at bundle time, but do not establish how the compromise occurred.
- Remove the affected versions, use independently verified earlier releases, and treat hosts that imported them as potentially compromised; isolate them and rotate accessible credentials.
Article Details
- Attack Vectors
- The two compromised @joyfill beta releases contain an obfuscated JavaScript implant appended to package code. In @joyfill/layouts, importing the CommonJS entrypoint starts the implant without an npm lifecycle hook.
- The loader resolves encrypted JavaScript through Tron or Aptos pointers and BNB Smart Chain transactions, then evaluates the recovered code. A parallel branch starts a detached Node.js process that requests and evaluates a decrypted /$/boot response.
- The recovered remote-access payload supports JavaScript and shell-command execution, file upload, clipboard access, and persistence through modifications to developer-tool files.
- Matching downstream boot captures can provision Python and request a Python credential-stealing payload. The source does not establish that every affected Joyfill host received those captured responses.
- Defensive Notes
- Remove both affected versions from lockfiles, caches, mirrors, build images, and deployment artifacts; block their restoration through dependency resolution. The source recommends independently verified earlier versions and avoiding the beta dist-tag until Joyfill confirms remediation.
- npm install --ignore-scripts does not prevent execution when the affected module is imported.
- Treat hosts that imported either affected version as potentially compromised. Isolate them, preserve logs and dependency artifacts, and rotate reachable credentials from a separate, uncompromised machine.
- Investigate unexpected changes to the identified VS Code, Cursor, Antigravity, Discord Desktop, GitHub Desktop, and global npm files. If the Python follow-on may have run, check the reported .npm staging directories and rotate exposed browser, wallet, and password-manager data.
- Review endpoint and CI telemetry for detached Node.js processes, the reported C2 IPs, Sec-V headers, and unexpected blockchain RPC traffic from build agents or developer workstations.
Indicators of compromise
| Type | Indicator | Context |
|---|---|---|
| IPV4 | 166[.]88[.]134[.]62 | Socket.IO C2 endpoint and upload host selected for the Joyfill marker. |
| IPV4 | 198[.]105[.]127[.]210 | Alternate C2 profile embedded in the recovered loaders. |
| IPV4 | 23[.]27[.]13[.]43 | Host selected by the Joyfill detached branch for its boot-payload request. |
| IPV4 | 23[.]27[.]202[.]27 | Alternate C2 profile embedded in the recovered loaders. |
| SHA256 | 1352ad22c99983d91e600348b7cbf58235131b1ee34cea9f09623206d5b7dea7 | Compromised components dist/index.js. |
| SHA256 | 26351aed0397158d3a3b8cc8fd3047d4c015d264c9895f10f20f1521b974ed18 | Recovered final clientCode remote-access payload. |
| SHA256 | 26e679eaf1e9baeb7c55eb48db482301171d4d26e1728544b23734a90dc70e1b | Preserved malicious /$/boot capture; its delivery to a specific infected Joyfill host was not established. |
| SHA256 | 2cfede38fb121a71a2f3607474aa8cd588a99f51b37e5e6f0d8cb789fa275032 | Preserved malicious /$/boot capture; its delivery to a specific infected Joyfill host was not established. |
| SHA256 | 36ff00b45e67baa7e3674b0c80f48e88737264c61e5c6b3b091200972de8157c | Captured Python credential-stealing payload. |
| SHA256 | 5f6a92006ca2ea4b464d66fb41af777edce7296939a7c6ee491e2b3cbfe09848 | Compromised layouts ESM bundle. |
| SHA256 | 67c6ef602cc850f10d935fee53fa40440df841adf081563bf4fc2631a71249ce | Compromised components dist/index.esm.js. |
| SHA256 | 78f0de8682e0e894a5784eb7e95db4da6088f528918ca3107dd1e76f80a561d8 | Recovered detached-branch JavaScript payload. |
| SHA256 | 8e8b90dedd456ded0c5748119836e1ca1066112bc569c1b41ca70eb931d1d4dc | Compromised layouts CommonJS bundle. |
| SHA256 | adc4af90540d33cd1e98f44b51482ae9250fbeb97d6f8d7841c81b618cb2c6e6 | Compromised @joyfill/layouts package archive. |
| SHA256 | ae7565109fd01b88d82acf7f73ab20709cbc2c9f26fdea13e429ccc87a55d4fb | Decoded malicious detached bootstrap. |
| SHA256 | bcc93dc55bc7daedf4ca57254f0e7a7f1c40e09851eab98fe10cde801982db17 | Compromised @joyfill/components package archive. |
| SHA256 | c5742ea1875ecd2360022624149994909cd0546e221e4203dffd01f48de45469 | Compromised components dist/joyfill.min.js. |
| SHA256 | cb46f12d70824ea24ed1f8bcf45bf3f86680e02a9089aafc03b27f691be57be3 | Recovered in-process JavaScript loader. |
| SHA256 | f452f9cfa539f4a1fe25187a99a484391290d5dbaa422ba455edf6b04f81b7d1 | Decoded malicious tier-two resolver. |
MITRE ATT&CK
T1027 · Obfuscated Files or InformationThe package implant and recovered payloads use JavaScript obfuscation, including character shuffling and compressed string recovery.T1027.013 · Encrypted/Encoded FileThe loader XOR-decrypts blockchain-retrieved code, and the detached branch decrypts its boot response before evaluation.T1059.004 · Unix ShellThe recovered remote-access payload supports shell-command execution on affected hosts.T1059.006 · PythonCaptured downstream bootstraps can provision Python and request a Python credential-stealing payload.T1059.007 · JavaScriptImporting the affected package runs JavaScript that evaluates recovered stages; the RAT can also evaluate supplied JavaScript.T1071.001 · Web ProtocolsPayload stages use web requests for boot-payload retrieval, check-ins, additional JavaScript, and uploads.T1105 · Ingress Tool TransferThe detached branch downloads a boot payload, while downstream code can retrieve further JavaScript and a Python payload.T1115 · Clipboard DataThe recovered remote-access payload reads clipboard data using operating-system-specific commands.T1195.002 · Compromise Software Supply ChainMalicious JavaScript was present in two published @joyfill npm beta releases.
Malware
DEV#POPPERSocket.IO command set, Sec-V marker design, and developer-tool persistence associated with the DEV#POPPER malware family. These are family assessments based on direct code overlap and published technicalOmniStealerhandling for browser decryption. We assess with medium likelihood that this is an iteration of the OmniStealer malware.PolinRiderThe loader has exact PolinRider-family indicators, including its multi-chain resolver structure, global markers, and XOR keys. The recovered 77 KB final JavaScript has the highly distinctive Socket.IO command set, Sec-V
Vendors
Products
@joyfill/componentsdevelopment kits for embedding forms, documents, and PDFs into web and mobile applications. @joyfill/components supplies the React UI components used to build, render, and edit these experiences, while@joyfill/layoutssupplies the React UI components used to build, render, and edit these experiences, while @joyfill/layouts manages their page and field layouts.Antigravityby developer tooling. Its targets include the @vscode/deviceid module inside VS Code, Cursor, and Antigravity; Discord Desktop’s core module; GitHub Desktop’s resources/app/main.js; and the global npm CLI atCursorroutinely executed by developer tooling. Its targets include the @vscode/deviceid module inside VS Code, Cursor, and Antigravity; Discord Desktop’s core module; GitHub Desktop’s resources/app/main.js; and the globalDiscord Desktoptooling. Its targets include the @vscode/deviceid module inside VS Code, Cursor, and Antigravity; Discord Desktop’s core module; GitHub Desktop’s resources/app/main.js; and the global npm CLI atGitHub Desktopthe @vscode/deviceid module inside VS Code, Cursor, and Antigravity; Discord Desktop’s core module; GitHub Desktop’s resources/app/main.js; and the global npm CLI at node_modules/npm/lib/cli.js. The injection tagsNode.jsAptos, and BNB Smart Chain transactions. Static analysis shows that its primary branch reaches a 77 KB Node.js remote-access trojan. A parallel branch launches a detached Node.js process, requests a separate bootnpmTwo npm beta releases in the @joyfill namespace contain an import-time JavaScript implant that resolves encrypted code through Tron, Aptos, and BNB Smart Chain transactions. Static analysis shows that its primary branchVS Codethat are routinely executed by developer tooling. Its targets include the @vscode/deviceid module inside VS Code, Cursor, and Antigravity; Discord Desktop’s core module; GitHub Desktop’s resources/app/main.js; and the