TL;DR
Smart contracts are being weaponized as command-and-control (C2) infrastructure for malware. The technique — called EtherHiding — stores malicious payloads and C2 addresses on-chain, making them virtually impossible to take down. In March 2026 alone, three major campaigns were discovered: EtherRAT (a Node.js backdoor hiding C2 in Ethereum contracts), a North Korean state-sponsored operation (UNC5342 using transaction history as dead-drop resolvers), and a supply chain attack via a malicious NPM package (jest-fet-mock).
This article breaks down how EtherHiding works at the smart contract level, provides detection patterns for both blockchain developers and SOC teams, and offers a defense playbook for organizations operating in the Web3 space.
Why Traditional Takedowns Don't Work
When law enforcement shuts down a traditional C2 server, the malware loses its brain. Domain seizures, IP blacklisting, hosting provider takedowns — these tools have worked for decades.
EtherHiding breaks this model entirely:
Traditional C2:
Malware → DNS lookup → C2 server (can be seized/blocked)
EtherHiding C2:
Malware → eth_call to smart contract → reads C2 address from on-chain storage
→ connects to current C2 server
→ if server is seized, attacker updates contract → malware auto-reconnects
The blockchain is the intermediary, and it has three properties that make it ideal for attackers:
- Immutability: Once deployed, the contract exists forever. No one can "take it down."
- Availability: Public RPC endpoints (Infura, Alchemy, Ankr) provide free, anonymous read access — no authentication required.
- Updateability: If the contract includes a setter function, the attacker can rotate C2 addresses for the cost of a single transaction (~$0.50 on Ethereum, ~$0.01 on BNB Chain).
How EtherHiding Works: The Smart Contract Layer
The Minimal C2 Contract
At its simplest, an EtherHiding C2 contract looks like this:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Config {
address private owner;
string private data; // Stores C2 URL or encoded payload
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
// Attacker updates C2 address with a single tx
function set(string calldata _data) external onlyOwner {
data = _data;
}
// Malware reads C2 address — free eth_call, no tx needed
function get() external view returns (string memory) {
return data;
}
}
The malware client side is equally simple:
// EtherHiding client — retrieves C2 from on-chain storage
const { ethers } = require('ethers');
const RPC = 'https://rpc.ankr.com/eth'; // Free, no auth
const CONTRACT = '0x<attacker_contract>';
const ABI = ['function get() view returns (string)'];
async function getC2() {
const provider = new ethers.JsonRpcProvider(RPC);
const contract = new ethers.Contract(CONTRACT, ABI, provider);
const c2Url = await contract.get();
return c2Url; // e.g., "https://cdn-update.example[.]com/api"
}
The Dead-Drop Resolver Pattern (UNC5342)
North Korean threat actor UNC5342 takes a more sophisticated approach — instead of storing data in contract storage, they use transaction history as a dead-drop:
1. Attacker sends a transaction to a known address
2. The transaction input data contains the encoded C2 URL
3. Malware queries eth_getTransactionByHash() to read the payload
4. No contract needed — just regular transactions on an EOA
This is harder to detect because there's no contract to analyze. The "C2 infrastructure" is just data embedded in normal-looking transactions.
The NPM Supply Chain Vector
The jest-fet-mock package discovered in March 2026 combined EtherHiding with supply chain poisoning:
1. Attacker publishes jest-fet-mock to NPM (looks like a testing utility)
2. Package includes a postinstall script
3. Script queries an Ethereum smart contract for the current payload URL
4. Downloads and executes platform-specific malware (Win/Linux/Mac)
5. Malware steals crypto wallets, cloud credentials, SSH keys
The blockchain query in the install script looks like a legitimate Web3 dependency — easy to miss in code review.
Detection: What to Look For
For SOC Teams: Network-Level Indicators
1. Unexpected RPC calls from non-Web3 applications
If your CI/CD pipeline, developer workstations, or production servers are making calls to Ethereum RPC endpoints but don't run any Web3 applications, that's a red flag.
# Monitor for RPC calls to known public endpoints
# Common public RPC endpoints used by EtherHiding
ENDPOINTS=(
"rpc.ankr.com"
"mainnet.infura.io"
"eth-mainnet.g.alchemy.com"
"bsc-dataseed.binance.org"
"rpc.ftm.tools"
"api.avax.network"
)
# Suricata rule example
# alert http any any -> any any (
# msg:"Potential EtherHiding - eth_call to public RPC";
# content:"eth_call"; http_client_body;
# content:"rpc.ankr.com"; http_host;
# sid:2026001; rev:1;
# )
2. Look for eth_call and eth_getStorageAt in process command lines
# Hunt for processes making blockchain queries
ss -tnp | grep -E '(8545|443)' | grep -v expected_web3_apps
# Check for ethers/web3 libraries loaded by unexpected processes
find /proc/*/maps -readable 2>/dev/null | \
xargs grep -l 'ethers\|web3' 2>/dev/null | \
grep -v expected_apps
3. Elastic Security detection rule
Elastic already ships a built-in rule for EtherHiding (as of 8.19):
# Elastic SIEM - Potential EtherHiding C2 via Blockchain Connection
rule.name: "Potential EtherHiding C2 via Blockchain Connection"
# Triggers on: outbound connections to known RPC endpoints
# from processes that aren't known Web3 applications
# Combined with: eth_call or similar JSON-RPC methods in request body
For Blockchain Developers: On-Chain Analysis
1. Identify suspicious "config" contracts
# Python script to scan for potential EtherHiding contracts
from web3 import Web3
w3 = Web3(Web3.HTTPProvider('https://rpc.ankr.com/eth'))
def analyze_contract(address):
"""Check if a contract looks like an EtherHiding config store."""
code = w3.eth.get_code(address)
if len(code) < 500: # Suspiciously small contract
bytecode_hex = code.hex()
indicators = {
'has_sstore': '55' in bytecode_hex,
'has_sload': '54' in bytecode_hex,
'tiny_contract': len(code) < 300,
'few_functions': bytecode_hex.count('63') < 5,
}
score = sum(indicators.values())
return score >= 3, indicators
return False, {}
2. Monitor contract interactions from known malware addresses
Cross-reference contract callers against threat intelligence feeds. If an address flagged by Chainalysis or Elliptic is reading from a contract's get() function, investigate the contract.
3. Scan NPM packages for blockchain dependencies
# In your CI/CD pipeline, flag unexpected web3/ethers dependencies
npm ls | grep -iE 'ethers|web3|@ethersproject' | \
grep -v "node_modules/your-expected-web3-deps"
# Check postinstall scripts for RPC calls
find node_modules -name "package.json" -exec \
grep -l "postinstall" {} \; | while read pkg; do
dir=$(dirname "$pkg")
grep -rl "eth_call\|getStorageAt\|ankr\|infura" "$dir" 2>/dev/null
done
Defense Playbook
For Organizations Running Web3 Infrastructure
| Layer | Action | Priority |
|---|---|---|
| Network | Whitelist RPC endpoints; alert on unexpected blockchain queries | High |
| Endpoint | Monitor for ethers/web3 library loading in non-Web3 processes | High |
| Supply Chain | Audit NPM/pip/cargo dependencies for hidden blockchain calls | Critical |
| SIEM | Add EtherHiding detection rules (Elastic, Splunk, Sentinel) | High |
| Threat Intel | Integrate on-chain indicators into your IOC feeds | Medium |
| DNS | Block or alert on known public RPC provider domains from prod servers | Medium |
For DeFi Protocol Teams
If your protocol's smart contracts are being abused as EtherHiding infrastructure:
- You can't prevent it — public blockchains are permissionless
-
You can detect it — monitor for contracts with minimal bytecode that receive frequent
eth_callreads but rare state-changing transactions - You can report it — share contract addresses with threat intel platforms (Chainalysis, TRM Labs, Elliptic)
For Individual Developers
# Before installing any NPM package, check for hidden blockchain deps
npx npm-audit-ci --critical
# Use lockfiles and pin exact versions
npm ci # Instead of npm install
# Review postinstall scripts of new dependencies
npm pack <package> && tar -xzf <package>.tgz && cat package/package.json
# Consider using Socket.dev or Snyk for supply chain monitoring
The Uncomfortable Truth
EtherHiding exploits a fundamental property of public blockchains: permissionless, censorship-resistant data storage. The same properties that make Ethereum valuable for DeFi make it valuable for malware operators.
There's no silver bullet fix. You can't add a "malware filter" to Ethereum without breaking its core properties. The defense has to happen at the edges — monitoring network traffic, auditing dependencies, and detecting the behavioral patterns that distinguish legitimate Web3 usage from malicious blockchain queries.
The March 2026 campaigns (EtherRAT, UNC5342, jest-fet-mock) demonstrate that EtherHiding has moved from proof-of-concept to production-grade attack infrastructure. Nation-state actors are using it. Supply chain attacks are leveraging it. And the cost for attackers is negligible — a few dollars in gas fees for infrastructure that's essentially bulletproof.
If your organization interacts with blockchain technology in any capacity, EtherHiding detection should be in your threat model. If it isn't, you're defending against yesterday's attacks.
Quick Reference: IOCs and Detection Resources
Known EtherHiding RPC endpoints to monitor:
-
rpc.ankr.com/eth(and /bsc, /polygon variants) mainnet.infura.io/v3/*eth-mainnet.g.alchemy.com/v2/*bsc-dataseed.binance.orgcloudflare-eth.com
Detection rules:
- Elastic Security 8.19+: Built-in EtherHiding detection rule
- Suricata: Monitor for
eth_callin HTTP body to RPC endpoints - YARA: Scan for ethers/web3 library strings in unexpected binaries
Threat intel sources:
- Google GTIG: DPRK Adopts EtherHiding
- Picus Security: EtherHiding Simulation Guide
- Infosecurity Magazine: EtherRAT Campaign
Part of the DeFi Security Research series. Follow for weekly deep-dives into smart contract exploits, audit techniques, and defense patterns.
Top comments (0)