Joyfill npm Scope Compromised: Beta Packages Deliver PolinRider Blockchain C2 Loader and RAT
Two beta versions in the @joyfill npm scope, published on July 28, 2026, carried the same blockchain C2 loader seen in the earlier astro.config.mjs attack, which the article ties to the PolinRider campaign. The attacker published through the legitimate scope (a form-builder SDK with three maintainers) under the beta dist-tag. The malicious versions were live for roughly 10 hours, though the article also says clean versions were pushed within 3 hours. They remain cached on mirrors such as registry.npmmirror.com. The Tron dead drop address and BSC relay wallet are identical to the earlier campaign, which the article takes as confirmation of the same operator. The final stage is a 77KB RAT client matching the PolinRider bot client.
Detalhes técnicos
- Chain:
@joyfill/componentsbeta depends on@joyfill/[email protected], which holds the payload. Nothing runs at install time (no preinstall/postinstall hooks). The code executes when the package isrequire()d or imported, so any process that loaded it is exposed. - Injection: 62 obfuscated lines were inserted into
dist/index.cjs.jsanddist/index.es.js. They set the campaign markerglobal['!']='9-0135-3', exposerequireandmoduleglobally, and use three layers of character-shuffle obfuscation to reach the Function constructor. - Stage 1: The loader queries Tron (api.trongrid.io), reverses the hex-decoded
raw_data.datato get a BSC transaction hash, then fetches that transaction from bsc-dataseed.binance.org (fallback bsc-rpc.publicnode.com). It splits the input on?.?, XOR-decrypts with key2[gWfGj;<:-93Z^C, and runs the result witheval(). Aptos is used as a fallback source. A fallback channel (keym6:tTh^D)cBz?NM]) launches a detached hiddennode -eprocess for persistence. - Stage 2: Selects an HTTP C2 from the campaign marker prefix. For this payload that is
166.88.134[.]62. The other two servers in the routing logic are198.105.127[.]210and23.27.202[.]27. It then performs a second Tron-to-BSC fetch (Tron address TA48dct6rFW8BXsiLAtjFaVFoSuryMjD3v). - Stage 3: A 77KB LZ-compressed RAT client with PolinRider fingerprints (XB3pRQO/IvUhGI, veN854, lpVxjTQ, iwd7Ox). It is delivered entirely via the blockchain dead drop, skipping the HTTP /$/boot beacon used in the astro attack.
- Detection: Early network traffic goes only to legitimate public blockchain APIs, which makes network-based detection harder.
Remediação
- Check lockfiles for
@joyfill/layouts0.1.2-2773.beta.0 and the matching@joyfill/componentsbeta version. - Rotate all secrets present in any environment where
npm installor a build ran, or where the package was loaded. - Block or monitor the listed C2 IPs, and alert on unusual build-host access to Tron, BSC and Aptos APIs.
- Purge the malicious versions from internal registry mirrors and caches.
Linha do tempo
-
Joyfill npm Scope Compromised: Beta Packages Deliver PolinRider Blockchain C2 Loader and RAT
ler a análise desta fonte ocultar
Two beta versions in the @joyfill npm scope, published on July 28, 2026, carried the same blockchain C2 loader seen in the earlier astro.config.mjs attack, which the article ties to the PolinRider campaign. The attacker published through the legitimate scope (a form-builder SDK with three maintainers) under the beta dist-tag. The malicious versions were live for roughly 10 hours, though the article also says clean versions were pushed within 3 hours. They remain cached on mirrors such as registry.npmmirror.com. The Tron dead drop address and BSC relay wallet are identical to the earlier campaign, which the article takes as confirmation of the same operator. The final stage is a 77KB RAT client matching the PolinRider bot client.
Technical Details
- Chain:
@joyfill/componentsbeta depends on@joyfill/[email protected], which holds the payload. Nothing runs at install time (no preinstall/postinstall hooks). The code executes when the package isrequire()d or imported, so any process that loaded it is exposed. - Injection: 62 obfuscated lines were inserted into
dist/index.cjs.jsanddist/index.es.js. They set the campaign markerglobal['!']='9-0135-3', exposerequireandmoduleglobally, and use three layers of character-shuffle obfuscation to reach the Function constructor. - Stage 1: The loader queries Tron (api.trongrid.io), reverses the hex-decoded
raw_data.datato get a BSC transaction hash, then fetches that transaction from bsc-dataseed.binance.org (fallback bsc-rpc.publicnode.com). It splits the input on?.?, XOR-decrypts with key2[gWfGj;<:-93Z^C, and runs the result witheval(). Aptos is used as a fallback source. A fallback channel (keym6:tTh^D)cBz?NM]) launches a detached hiddennode -eprocess for persistence. - Stage 2: Selects an HTTP C2 from the campaign marker prefix. For this payload that is
166.88.134[.]62. The other two servers in the routing logic are198.105.127[.]210and23.27.202[.]27. It then performs a second Tron-to-BSC fetch (Tron address TA48dct6rFW8BXsiLAtjFaVFoSuryMjD3v). - Stage 3: A 77KB LZ-compressed RAT client with PolinRider fingerprints (XB3pRQO/IvUhGI, veN854, lpVxjTQ, iwd7Ox). It is delivered entirely via the blockchain dead drop, skipping the HTTP /$/boot beacon used in the astro attack.
- Detection: Early network traffic goes only to legitimate public blockchain APIs, which makes network-based detection harder.
Remediation
- Check lockfiles for
@joyfill/layouts0.1.2-2773.beta.0 and the matching@joyfill/componentsbeta version. - Rotate all secrets present in any environment where
npm installor a build ran, or where the package was loaded. - Block or monitor the listed C2 IPs, and alert on unusual build-host access to Tron, BSC and Aptos APIs.
- Purge the malicious versions from internal registry mirrors and caches.
- Chain: