A fresh supply chain scare hit software teams after attackers slipped malware into trusted open source libraries.
On July 28, 2026, malicious beta builds of two Joyfill packages appeared on the npm registry. The libraries, @joyfill/components and @joyfill/layouts, are used for forms and layout work in many web apps.
Anyone who imported those beta builds could trigger hidden code without a classic install script. The malware opens a remote control channel and later tries to steal developer secrets from the workstation.
Advice such as npm install with ignore scripts does not stop this threat because the code sits inside the package bundles themselves.
Analysts from StepSecurity identified the campaign after automated scans marked one layouts build as critical.
StepSecurity said in a report shared with Cyber Security News (CSN) that the same obfuscated implant appears in both packages and only in the published tarballs, not in clean project source.
The firm confirmed the finding through sandbox runs and by comparing malicious builds with earlier safe releases.
The impact reaches far beyond a single project. Once active, the malware can plant itself into tools developers open every day, including code editors and the global npm command line.

That worm style behavior means one infected machine can keep reloading the threat and may pass it into new packages. Teams that pulled any 2773 prerelease should treat those machines as compromised until cleaned.
This case fits a wider pattern of open source abuse where attackers prefer real projects over fake names.
Similar waves of npm package compromise have shown how quickly stolen tokens and keys can unlock further access across cloud platforms and code hosting accounts.
Hijacked Joyfill npm Packages
The attack chain has five stages that start the moment an application imports the package.
A hidden loader first sets a campaign tag and exposes Node features under short global names. It then reads public blockchain data to learn where the live control server sits, so the real address is not hard coded inside the package.
After that lookup, the malware evaluates more code in memory and connects through Socket.IO.
Operators can request host details, steal clipboard content, move files, and run scripts on the victim system.
The agent also injects copies of itself into VS Code modules, Cursor, Discord, GitHub Desktop, and the npm CLI so the threat returns after restarts.
That self spread is what makes the implant feel worm like in practice. Patching the global npm CLI is especially dangerous because every later npm command can re run the loader.

The design echoes earlier supply chain worm activity where one foothold tried to widen across everyday developer tooling.
Campaign tags steer victims toward different control hosts. For the npm path tagged A9-0135-3, traffic points at a dedicated address used for the socket channel and file uploads.
A staged Python helper later gathers browser data, wallet extensions, password managers, Git tokens, and keychains for upload.
Credential Theft and Recovery Steps
The real prize is the developer laptop rather than a short lived build runner. Stolen browser secrets, source control tokens, and npm credentials can open private repositories, cloud accounts, and package publishing rights.
Defenders watching for plain HTTP socket traffic, odd child Node processes, or unexpected edits inside editor and npm files will catch signs pure registry checks may miss.
If any 2773 beta of these Joyfill packages landed in a lockfile, remove those versions and pin to known good releases published before July 28, 2026.
Delete node_modules and reinstall from a clean lockfile so the injected bundle is gone. On machines that imported the code, inspect developer tool files for injection markers and reinstall those apps when markers appear.
Rotate every secret that lived on affected systems, including browser stored passwords, Git tokens, npm tokens, and wallet keys. Review outbound logs for the control hosts listed by the researchers.
The episode also aligns with other recent remote access trojan threats and cases where malicious packages steal secrets from engineering workstations at scale.
Organizations should treat import time execution as a first class risk during dependency review. Continuous lockfile checks and unusual Node egress monitoring remain practical defenses while teams respond.
Indicators of compromise (IoCs):-
| Type | Indicator | Description |
|---|---|---|
| Package version | @joyfill/components@4.0.0-rc24-2773-beta.4 | Compromised npm package version |
| Package version | @joyfill/components@4.0.0-rc24-2773-beta.5 | Compromised npm package version |
| Package version | @joyfill/components@4.0.0-rc24-2773-beta.6 | Compromised npm package version |
| Package version | @joyfill/layouts@0.1.2-2773.beta.0 | Compromised npm package version |
| Package version | @joyfill/layouts@0.1.2-2773.beta.1 | Compromised npm package version |
| Package version | @joyfill/layouts@0.1.2-2773.beta.2 | Compromised npm package version |
| IP address | 166.88.134.62 | C2 host (ports 443 and 80); npm campaign SOCKET_URL / UPLOAD_URL |
| IP address | 23.27.13.43 | Serves /$/boot downloader path |
| IP address | 198.105.127.210 | Alternate campaign C2 host |
| IP address | 23.27.202.27 | Alternate campaign C2 host (port 443; upload on 27017) |
| URL path | /$/boot | Stage 2B boot payload request path |
| URL path | /u/e, /u/f, /0x/js, /verify-human/, /snv | C2 request paths |
| Domain | api.trongrid.io | Blockchain C2 resolver endpoint (Tron) |
| Domain | fullnode.mainnet.aptoslabs.com | Blockchain C2 fallback (Aptos) |
| Domain | bsc-dataseed.binance.org | BNB Smart Chain RPC used in C2 resolve |
| Domain | bsc-rpc.publicnode.com | Alternate BSC RPC used in C2 resolve |
| Domain | ip-api.com | Geolocation lookup used by RAT |
| Tron address | TMfKQEd7TJJa5xNZJZ2Lep838vrzrs7mAP | Tron pointer address in C2 resolve |
| Tron address | TXfxHUet9pJVU1BgVkBAbrES4YUc1nGzcG | Tron pointer address in C2 resolve |
| Tron address | TA48dct6rFW8BXsiLAtjFaVFoSuryMjD3v | Re-armed Tron pointer stored by Stage 2 |
| SHA-256 | 26351aed0397158d3a3b8cc8fd3047d4c015d | Final Socket.IO RAT hash (as reported; truncated in source) |
| SHA-256 | 36ff00b45e67baa7e3674b0c80f48e8873726 | Python credential stealer hash (as reported; truncated in source) |
| Campaign marker | 9-0135-3 / A9-0135-3 | Campaign tag and Sec-V header value |
| File marker | C250617A, C250618A, C250619A, C250620A, C260511A, C260512A, RS260605 | Injection sentinel tags in developer tool files |
| File path | %USERPROFILE%.npm or /tmp/.npm | Credential staging directory |
| File path | npm/lib/cli.js | Global npm CLI injection target |
| File path | dist/index.es.js / dist/index.cjs.js | Malicious bundle entry points in layouts package |
Note: IP addresses and domains are intentionally defanged (e.g., [.]) to prevent accidental resolution or hyperlinking. Re-fang only within controlled threat intelligence platforms such as MISP, VirusTotal, or your SIEM.