PolinRider is a DPRK-linked software supply-chain malware campaign and multi-stage JavaScript loader associated with Lazarus/Contagious Interview activity. It compromises developer environments and legitimate software distribution channels, including source-code repositories, npm packages, Go modules, Rust crates, and browser-extension distribution. Malicious code is commonly injected into otherwise legitimate project configuration files, IDE task definitions, disguised non-code assets, or production bundles while preserving normal package functionality. Execution can occur when a developer opens a compromised project in Visual Studio Code-compatible editors or imports a compromised Node.js package; some variants also execute through package-install lifecycle hooks.
The loader uses public blockchain transaction data as a dead-drop resolver to locate and retrieve encrypted follow-on stages, then decrypts and dynamically executes them. It supports detached background execution, allowing payloads to outlive the initiating editor or process. Recovered follow-on payloads include a Node.js remote-access trojan with remote command execution, file operations, host and clipboard collection, and persistence through modifications to developer-focused applications. Other associated stages have been observed stealing developer credentials, browser and cryptocurrency-wallet data, Git and package-registry tokens, and cloud credentials. Compromised developer credentials can subsequently be used to clone repositories, inject backdoored commits, and publish further malicious releases, supporting automated propagation across software ecosystems.
PolinRider predominantly targets individual developers and their development, CI, and build environments. Its tooling has been observed on Windows, macOS, and Linux systems. The campaign has been linked to fake-interview lures, poisoned repositories, malicious IDE configuration, typosquatted packages, and compromise of legitimate maintainer accounts and build environments.
Mallory pivots from this family to the IOCs, detections, and named campaigns that touch your stack, and pages you when something new lands.
3 distinct threat actors attributed by public researchers. Open in Mallory to see the full evidence chain and overlapping campaigns.
PolinRider is supply-chain campaign that hides obfuscated JavaScript inside compromised developers' .vscode/tasks.json files, fake .woff2 fonts, and legitimate config files like tailwind.config.js, postcss.config.mjs, eslint.config.mjs, App.js and babel.config.cjs.
북한 라자루스(Lazarus)로 추정 구글 크롬 웹 스토어 PolinRider 악성코드 분석-YouTube Translator: Captions, Transcript & AI Summary로 유포되고 있는 악성코드
Security researchers have uncovered a campaign called PolinRider that hides malicious JavaScript loaders inside trusted code repositories, waiting for unsuspecting developers to run them.
27 distinct techniques documented for this family, organized by ATT&CK tactic.
Every push in both bursts is attributed by GitHub’s server to the DiogoAngelim identity, meaning either the account’s credentials (PAT, OAuth grant, SSH key, or the CI’s GITHUB_TOKEN) are directly in the operator’s possession
PolinRider is supply-chain campaign that hides obfuscated JavaScript inside compromised developers' .vscode/tasks.json files, fake .woff2 fonts, and legitimate config files like tailwind.config.js, postcss.config.mjs, eslint.config.mjs, App.js and babel.config.cjs.
Every push in both bursts is attributed by GitHub’s server to the DiogoAngelim identity, meaning either the account’s credentials (PAT, OAuth grant, SSH key, or the CI’s GITHUB_TOKEN) are directly in the operator’s possession
[The payload] ran it with eval and as a detached background process that outlives the editor.
The task was set to "runOn": "folderOpen" with "reveal": "never", so it started on its own and showed nothing.
The fallback C2 path adds persistence: if the primary eval() fails, the payload is launched as a detached node -e child process with windowsHide: true and stdio: 'ignore'
Every push in both bursts is attributed by GitHub’s server to the DiogoAngelim identity, meaning either the account’s credentials (PAT, OAuth grant, SSH key, or the CI’s GITHUB_TOKEN) are directly in the operator’s possession
[The payload] ran it with eval and as a detached background process that outlives the editor.
L’implant utilise un mécanisme de résolution de payload via des transactions blockchain publiques (Tron, Aptos, BNB Smart Chain) pour récupérer du code chiffré, le déchiffrer par XOR, et l’évaluer dynamiquement.
That file is not a font. It is 32,645 bytes of obfuscated JavaScript. The fifteen real FontAwesome files next to it were camouflage.
Four weeks later, on July 14, they followed up with a sequel on "ViteVenom," seven typosquats targeting the Vite ecosystem.
fake .woff2 fonts... public/fonts/fa-solid-400.woff2, not a font. Plaintext JavaScript with a .woff2 extension.
The fallback C2 path adds persistence: if the primary eval() fails, the payload is launched as a detached node -e child process with windowsHide: true and stdio: 'ignore'
removed the visible symptom but missed mechanism... the fake public/fonts/fa-solid-400.woff2 payload disappeared from the shipped tarball... But the trigger, .vscode/tasks.json ... was left in place
Several of the pushed commits carry backdated author/committer dates... one on html-to-jsx-demo claims 2025-11-06 while the actual push arrived 2026-07-31
Every push in both bursts is attributed by GitHub’s server to the DiogoAngelim identity, meaning either the account’s credentials (PAT, OAuth grant, SSH key, or the CI’s GITHUB_TOKEN) are directly in the operator’s possession
Try Tron first... catch (e) { // Fallback to Aptos ... } ... try { txInput = await fetchFromBSC('bsc-dataseed.binance.org'); ... } catch (e) { txInput = await fetchFromBSC('bsc-rpc.publicnode.com'); }
"Joyfill npm Packages Compromised with Blockchain C2 Loader"
Loader de 5 849 octets configurant le endpoint Socket.IO (166.88.134.62:443) ... Requête vers 23.27.13.43/$/boot avec header Sec-V: A9-0135-3
The C2 resolution chain is identical... Tron ... The result is a BSC transaction hash. BSC ... decode ... XOR decrypt with the hardcoded key and eval().
It fetched a second stage from Ethereum JSON-RPC endpoints, using the blockchain as the delivery channel so there is no domain to block.
79 indicators attributed across vendor reports, sandbox runs, and researcher write-ups. Full values are available in Mallory.
IPs, domains, and DNS infrastructure linked to this family.
File hashes (MD5, SHA-1, SHA-256) from samples and reports.
Other indicator types observed in public reporting.
32 sources tracked across advisories, community write-ups, and news. New activity surfaces here as Mallory finds it.
A malicious PolinRider variant was embedded in a compromised greentic-setup-dev crate release. It would execute when a project that depended on the crate was opened in Visual Studio Code.
A PolinRider variant was embedded in a malicious greentic-setup crate release. It executed when a project that depended on the crate was opened in Visual Studio Code.
The content only identifies PolinRider via a hashtag in a post about malicious code executing when the BindsNET repository was cloned. It does not describe PolinRider's functionality or establish that it was the malicious code involved.
Supply-chain malware campaign that compromises legitimate developers and their GitHub/npm accounts, persists via hidden VS Code tasks and malicious JavaScript embedded in fake font files and legitimate config files, and spreads through software package releases.
Match every observed IP, domain, and hash against your live telemetry.
Named campaigns wielding this family, with evidence pinned to each claim.
CVEs this family uses for access and lateral movement.
YARA, Sigma, Snort, and vendor rules, auto-deployed to your SIEM.
Every documented technique, ranked by evidence weight.
Reddit, Mastodon, and CTI community discussion around this family.