Skip to content

Back to the catalog

Earliest Known PolinRider Malware Found in 2025 npm Packages
opensourcemalware.comwriteup

Earliest Known PolinRider Malware Found in 2025 npm Packages

OpenSourceMalware traces nine itsa-* npm package versions published on 4 May 2025 from a hijacked maintainer account to the PolinRider campaign, eight months before documented victims. It decodes the EtherHiding chain (BNB Smart Chain and Ethereum calldata, JADESNOW, INVISIBLEFERRET bootstrapper, Socket.IO RAT, Python stealer) and links the 2025 sample to 2026 force-push infections. It lists IOCs, hashes, a timeline and hunting guidance.

TL;DR Decodes a May 2025 npm account-takeover payload as an early PolinRider building block, with IOCs and hunting tips.
Document

What it is

OpenSourceMalware found that nine npm versions from the maintainer of the itsa-* packages, published 20:15 to 21:45 UTC on 4 May 2025, carry a payload matching the PolinRider campaign. The post's authors confirm the payload in four of the nine. The other five were removed before they could be read and are counted as infected because they sit in the same burst. The sample carries PolinRider's payload but not its force-push spread behaviour, so the authors call it a building block of the campaign.

Affected

Check lockfiles and node_modules for these versions. Three are still live on npm as of the post (late October 2026):

  • itsa-jsext@2.0.3
  • itsa-react-button@16.0.11
  • itsa-react-docviewer@16.1.2

Six have been removed from the registry: itsa-utils@1.4.2, itsa-cli@16.5.3, itsa-react-maskedinput@16.1.2, itsa-react-checkbox@16.0.5, itsa-react-focuscontainer@16.0.10 and itsa-react-input@16.1.2. A lockfile or mirror can still pin them.

The maintainer published seven clean replacements the next morning, including itsa-utils@1.4.3. These did not remove the infected versions, so anyone pinning a version can still install them.

The payload runs when an application imports the package. There are no install hooks. In index.js or webpack.config.js, a single long obfuscated line is appended after hundreds of spaces.

How it works

The chain uses EtherHiding. The encrypted stages stay in blockchain transaction calldata, and the loader fetches them through public explorer APIs.

  1. The loader sets global['_V']='5-itsa', queries Binplorer for the attacker wallet's latest transaction, decodes the calldata, XORs it with $v$5;kmc$ldm*5SA and runs it with node -e.
  2. JADESNOW sits in a BNB Smart Chain transaction dated 7 February 2025. It switches to Ethereum, reads one transaction via Ethplorer, BlockCypher and Blockchair, and decrypts it with ThZG+0jfXE6VAGOJ.
  3. The bootstrapper contacts 154.91.0.103:27017. It exits if ip-api.com reports country code RU. Otherwise it installs Node dependencies and Python 3.12.7, then reports to POST /verify-human/5-itsa.
  4. A Socket.IO RAT connects to 85.239.62.36:3306 and runs shell commands and file uploads. A 65,500-byte Python stealer runs on Windows, Linux and macOS.

The stealer targets nine browsers, more than 80 wallet extensions, Git credentials, GitHub CLI tokens, Solana keys, 1Password and Dashlane data, and cloud storage clients. It stages loot in %USERPROFILE%\.npm or /tmp/.npm and uploads AES-encrypted ZIPs to 85.239.62.36:27017/u/f. Telegram is the fallback for archives under 50 MB.

Nothing creates a run key, scheduled task, launch agent or service, so the malware does not survive a reboot. It stays alive through detached Node processes and Socket.IO reconnects every five seconds.

What to do

Hunt for:

  • Node command lines containing both -e and global['_V'].
  • Very long lines after runs of spaces in index.js or webpack.config.js, and the strings global['_V'], global.i= and global.o=.
  • Node processes querying Binplorer, Ethplorer, BlockCypher or Blockchair just before spawning node -e.
  • Node connections on port 3306 that speak HTTP or Socket.IO instead of MySQL.
  • Contact with 154.91.0.103, 85.239.62.36 or 85.239.60.213.
  • New tmp7A863DD6.tmp, /tmp/.npm, ~/.node_modules or ~/.pyenv created by Node processes.
  • Runtime installs of socket.io-client, pyzipper, pycryptodomex, portalocker or secretstorage by a dependency.
  • Telegram sendDocument traffic from developer machines.

For source repositories, look for GitHub force-pushes that change only webpack.config.js, keep the commit message and author date, and carry a committer date in a different timezone offset. Several repositories force-pushed within one minute is another sign. Trust GitHub push times over commit dates, because some July 2026 commits were back-dated by 34 to 152 days.

The post lists SHA-256 hashes for four tarballs and the payload stages, 10 infected 2026 commit SHAs, and blockchain addresses. The BNB Smart Chain wallet is 0x9BC1355344B54DEDf3E44296916eD15653844509. The Telegram bot is @file_1018_bot (ID 7870147428).

Caveats

  • The 2026 variants (B, B2, C) were not decoded, so it is unknown whether they use the same route. They were found only in the maintainer's GitHub repositories, never in npm.
  • The account-takeover explanation is the authors' inference. They note the burst used npm 10.9.2 and Node 22.14.0, while every other publish from May 2025 to April 2026 used npm 5.5.1 and Node 8.9.1. The npm client self-reports these versions, so they are not proof.
  • The authors suspect the infection stayed on the maintainer's machine from 2025 and drove the 2026 force-pushes. This is their reading of the evidence, not a confirmed finding.
  • Binplorer no longer accepts the loader's type=mint request, so that exact request fails today. The on-chain data remains and was recovered through public RPC.
  • The Telegram bot is send-only, and no victim archives were retrieved.
  • It is not known who removed the six packages from the registry.

Organisations named here

  • EtherHiding
  • Google Threat Intelligence Group
  • itsa-utils
  • JADESNOW

Technologies named here

  • ip-api.com
  • Telegram Bot API
  • npm
  • OpenSourceMalware
  • Google Threat Intelligence
  • Socket.IO
  • Node.js
  • Python
  • Ethereum
  • Telegram
  • GitHub
  • Binplorer
  • Blockchair
  • BlockCypher
  • Browsers targeted by the stealer: Chrome, Chromium, Opera, Opera GX, Brave, Edge, Arc, Vivaldi, Firefox
  • Cloud storage targeted: Dropbox, Google Drive, OneDrive, iCloud, Box, MEGA, pCloud
  • Ethplorer
  • npm/itsa-cli@16.5.3 (removed)
  • npm/itsa-jsext@2.0.3 (payload in index.js line 11)
  • npm/itsa-react-button@16.0.11 (payload in webpack.config.js line 26)
  • npm/itsa-react-checkbox@16.0.5 (removed)
  • npm/itsa-react-docviewer@16.1.2 (payload in webpack.config.js line 23)
  • npm/itsa-react-focuscontainer@16.0.10 (removed)
  • npm/itsa-react-input@16.1.2 (removed)
  • npm/itsa-react-maskedinput@16.1.2 (removed)
  • npm/itsa-utils@1.4.2 (removed)
  • Wallets and credential stores targeted: MetaMask, Phantom, Coinbase, Binance, Trust Wallet, TronLink, OKX, Ronin, Keplr, Rabby, Exodus, SafePal, 1Password, Dashlane, Electrum, Atomic

Techniques named here

  • EtherHiding
  • Account Takeover
  • Account takeover / compromised maintainer publishing
  • Code appended after whitespace padding
  • Detached process execution and silent error handling
  • Exfiltration of AES-encrypted ZIP archives
  • Geofencing kill switch
  • Git force-push of amended commits with backdated dates
  • Remote access via Socket.IO
  • Use of non-standard port for C2 (3306)
  • XOR decryption of staged payloads

Threat actors named here

  • PolinRider
  • TasksJacker
  • UNC5342
  • InvisibleFerret
  • BeaverTail
  • DPRK
  • JADESNOW (second-stage obfuscated loader reading Ethereum calldata via Ethplorer, BlockCypher and Blockchair)
  • North Korean payload (as described by the page)
  • Python credential stealer (65,500 bytes unpacked, exfiltrates via 85.239.62.36:27017/u/f with Telegram fallback)
  • Socket.IO RAT (Node.js, connects to 85.239.62.36:3306)