Threat intel
North Korea-linked malware hides its C2 in Ethereum transfers
A DPRK-linked campaign aimed at developers reads its server address from plain Ethereum transfers. How HashHiding works and what to block and hunt.
Researchers at Ransom-ISAC published an analysis on September 25 of a North Korea-linked malware campaign that finds its command-and-control (C2) server by reading ordinary Ethereum transfers. The operators encode the server's IP address and port into the recipient address of a transfer. Infected machines look up the latest transfer from one wallet, decode it and reconnect, so a single cheap transaction moves every victim to a new server.
The campaign, which Ransom-ISAC calls Cross-Chain TxDataHiding (XCTDH), goes after software developers through fake job offers on Telegram, weaponized GitHub repositories and trojanized npm packages. The Ethereum channel, named HashHiding, has been signalling since June 23, 2026, with 2,655 outbound transactions in 90 days. The report describes infrastructure and malware, not victims, and gives no count of infected machines. If your developers take take-home coding tests or install packages from outside a vetted registry, this is aimed at them.
How it works
Earlier blockchain tricks, such as the EtherHiding technique Google tied to North Korean operators in 2025, store data or code inside a smart contract. Defenders learned to flag the contract calls and the calldata (the input field of a transaction) that carried it. HashHiding uses neither. The transfers are plain coin movements from a signal wallet, 0x33ff3edaf55a8e03dcbc7cb40d498a49cd499891, and most of them send 0 wei; a few send 150 wei. Signalling costs the operators almost nothing.
The message is the recipient address itself. An Ethereum address is 20 bytes. The first four bytes are the C2 IPv4 address and the next two are the port. In the example the researchers decoded, the recipient 0xB5D6959401bbb5D69594005000ff8C84e0b715b1 starts with B5 D6 95 94, which is 181.214.149.148, followed by 01bb, which is port 443. Nobody is expected to hold the private key for an address built this way, so any value sent to it is lost, which is why the operators send none or almost none.
On the victim side, a JavaScript module the researchers label _Z does the lookup. It was found in a September 2026 response from the campaign's /init endpoint and runs alongside the rest of the implant. It calls the standard eth_getBlockByNumber JSON-RPC method against free public Ethereum nodes (ethereum-rpc.publicnode.com, eth.drpc.org and eth-mainnet.public.blastapi.io), walks back through recent blocks, picks out transactions sent from the signal wallet and decodes the newest recipient. The implant needs no API key and touches no attacker-owned domain or server until the final connection.
HashHiding is one of three recovery paths. The September samples resolve their C2 three ways in parallel: a hardcoded endpoint, an older chain that uses TRON and Aptos transactions to point at payloads stored on BNB Smart Chain, and the Ethereum signal. If defenders block the hardcoded IP, the operators send one transfer and every implant finds the replacement. A public blockchain cannot be seized or taken offline the way a domain or a rented server can.
What attackers are doing
The entry point is social engineering. A developer is approached on Telegram about a job and asked to clone a repository or install a package as part of a test. The malicious code hides in configuration files; in one case it was a one-line JavaScript downloader placed in a tailwind.config.js after more than a thousand whitespace characters, so it sits far off the right edge of an editor window and slips past a quick review.
Once it runs, the chain installs two payloads:
- DEV#POPPER.js, a cross-platform remote access trojan written for Node.js that can run commands, log keystrokes and watch the clipboard.
- OmniStealer, a Python credential stealer that collects browser data, password manager data, cloud storage credentials and cryptocurrency wallet material.
On chain, the signal wallet sent 2,655 beacon transactions between June 23 and September 21, 2026, and pointed at four C2 endpoints over that time: 23.27.20.187 on port 80, then port 443, then 181.214.149.147:443, then 181.214.149.148:443. The last two differ only in the final octet, which is easy to miss when you scan a list of indicators by eye.
What to do
Block the known infrastructure now. Add 23.27.20.187, 181.214.149.147 and 181.214.149.148 to your firewall and proxy deny lists on all ports. Expect these to change, since changing them costs the operators one transfer.
Hunt for the lookup, not only the addresses. On a normal developer laptop there is rarely a reason for a node process to call public Ethereum RPC nodes. Search DNS, proxy and EDR (endpoint detection and response) network logs for the three hostnames above, and flag any case where a query is followed within seconds by HTTP to a bare IP address. Also search source trees, node_modules folders and package caches for the wallet string 33ff3edaf55a8e03dcbc7cb40d498a49.
Check config files in recently cloned repos. Look for lines of extreme length or long runs of whitespace in files such as tailwind.config.js, postcss.config.js or next.config.js, especially followed by eval, Function( or a require of child_process. A pre-commit or CI check that rejects lines over a few hundred characters in config files catches this pattern cheaply.
Restrict egress to blockchain RPC. Allow public Ethereum, BNB Smart Chain, TRON and Aptos endpoints only for teams whose work needs them, and route those through a proxy that logs the calling process. For everyone else, a default deny turns HashHiding from a silent recovery path into a blocked request you can alert on.
Change how people run untrusted code. Treat any repository received during a hiring process as hostile: open it in a disposable VM or container with no access to SSH keys, cloud credentials or the corporate network. Set ignore-scripts=true in .npmrc (or run npm install --ignore-scripts) for untrusted projects, so preinstall and postinstall hooks do not run. Point developer machines at an internal registry proxy that holds new package versions for a few days before allowing them.
If you find it, rebuild. OmniStealer goes after exactly what a developer machine holds. Reimage the host rather than cleaning it, then rotate every credential it could reach: npm and GitHub tokens, SSH keys, cloud access keys, browser-saved passwords and any wallet keys. Review GitHub and npm audit logs for pushes or publishes you cannot explain, because a stolen token can turn one infected developer into a poisoned package.
Why IP blocklists fall short here
A C2 channel that lives on a public blockchain survives every takedown that relies on seizing a domain or asking a host to pull a server. The weak point is the lookup itself: the malware has to make a JSON-RPC call that ordinary office and developer machines seldom make. Teams that know which processes are allowed to talk to blockchain nodes can catch this family and the next one that copies it, even after the IPs have changed.
We review developer workstation controls, package policies and CI pipelines as part of safeguarding and hardening, and hunt for this kind of beaconing in security operations. If you want to know whether a hostile take-home repo would get anywhere in your environment, open the chat and Yaali, our AI agent, will pass your question to an engineer.
Sources: Ransom-ISAC, XCTDH Adopts Hash Hiding, Cyber Security News, GBHackers, Cyberpress, Google Threat Intelligence on EtherHiding.