
Compromised npm Packages: @joyfill/components and @joyfill/layouts Ship an Obfuscated Remote Access Trojan
StepSecurity dissects malicious beta versions of @joyfill/components and @joyfill/layouts published to npm on July 28, 2026, which inject a five-stage obfuscated payload that executes on import rather than via a postinstall hook, so npm install --ignore-scripts does not stop it. The chain resolves its C2 server by reading a transaction on the Tron blockchain (with Aptos as fallback), decrypts a BNB Smart Chain transaction to find the next stage, and deploys a Socket.IO remote access trojan with worm-like self-propagation that patches the global npm CLI, VS Code/Cursor's @vscode/deviceid module, Discord desktop, and GitHub Desktop, plus a Python credential stealer targeting browser data, wallets, and Git/GitHub tokens. The writeup includes fully deobfuscated source code, IOCs (C2 IPs, Tron addresses, file hashes), and results from detonating the packages under Harden-Runner in a sandbox.
What it is
A targeted supply-chain compromise of two hijacked npm packages, @joyfill/components and @joyfill/layouts, published July 28, 2026. Only the "2773" beta prereleases are malicious — confirmed on @joyfill/layouts@0.1.2-2773.beta.0, flagged CRITICAL with a security score of 0 and a REJECTED verdict by StepSecurity's OSS AI scan. The malicious code exists only in the published tarballs; there is no matching source change in the projects.
How it works
The implant is compiled into the package entry bundles and runs on import, not install — package.json has no install hooks, so npm install --ignore-scripts does not stop it. In @joyfill/components the block is appended after ~3.2 MB of legitimate React code; in @joyfill/layouts it is spliced into dist/index.cjs.js and dist/index.es.js:862. The loader plants a campaign marker (global["!"] = "9-0135-3"), then uses a seeded string-shuffle decoder plus a two-step Function-constructor ladder to reassign global.r = require and global.m = module — hiding require, module, Function, and eval from static analysis. Later stages resolve C2 via a public blockchain transaction and open a Socket.IO RAT.
Preconditions / Affected
Any repository, CI/CD pipeline, or developer machine that installed a 2773 prerelease of either package. Note the layouts malicious tarball is a partial build — ~45 KB versus ~322 KB for clean siblings — and only exports PDFRenderer, a useful triage signal.
What to do
If any 2773 prerelease of @joyfill/components or @joyfill/layouts was installed, treat those environments as compromised:
- Remove the affected versions.
- Pin to a known-good release published before July 28, 2026.
- Rotate any credentials present on affected machines.
Detection anchors from the page: the decoder at dist/index.es.js:862 beginning with the 9-0135-3 marker; the anomalous ~45 KB layouts tarball exporting only PDFRenderer.
Caveats
The hardcoded network indicators in the first two stages are only legitimate public blockchain APIs — the real C2 address is resolved at runtime and never appears as a literal, so scanning for a wallet address, socket.io, or the C2 host statically finds nothing. Every stage is decrypted in memory only.
flowchart TD
A[Project imports package] --> B[In-bundle loader<br/>index.es.js:862]
B --> C[global.r=require, global.m=module]
C --> D[Blockchain C2 resolver]
D --> E[Two staged downloaders]
E --> F[Socket.IO RAT + Python stealer]
G[npm install --ignore-scripts] -.does NOT block.-> A
H[Pin pre-2026-07-28 release] -->|cuts chain| AOrganisations named here
- A9-0135-3
Technologies named here
- StepSecurity Harden-Runner
- @joyfill/components
- StepSecurity OSS AI scan
- @joyfill/layouts
- @vscode/deviceid
- npm Package Cooldown and Compromised Package checks
- Discord desktop core module
- Dev Machine Guard
- GitHub Desktop
- npm CLI
- npm
- Node.js
- Python
- Socket.IO
- VS Code
- Cursor
- TRON
- Aptos
- BNB Smart Chain
Techniques named here
- Supply chain compromise via hijacked npm package
- Import-time execution
- Multi-layer string obfuscation
- Blockchain-based C2 resolution
- Detached child process persistence
- Campaign-gated branching
- Anti-analysis / sandbox evasion
- Dependency self-healing at runtime
- Socket.IO remote access trojan
- Clipboard and credential theft
- Worm-like self-propagation
Threat actors named here
- Unnamed threat actor
Related in Supply Chain


