Unmasking Wallet Drainers: Step-by-Step Breakdown of a Crypto Heist
Imagine visiting a seemingly harmless site to claim a free airdrop. You connect your wallet, and wait for the token to hit your wallet. Everything seems normal—until your assets start disappearing.
Welcome to the world of wallet drainers.
These attacks are more common—and more sophisticated—than you might think.
But how exactly do they work? Let’s break down the process step by step to see how wallet drainers operate - and what is happening behind the scenes.
What is a wallet drainer, and why should you care?
A wallet drainer is a piece of malicious code embedded in dApps that is designed to deceive users into surrendering control of their wallets.
Once access is granted, attackers can swiftly drain all available funds and assets—often without the user realizing it until it's too late.
These attacks are cleverly disguised as legitimate activities: enticing airdrops, exclusive giveaways, and even apps posing as well-known services.
It’s this seamless mimicry that makes them so effective—and so easy to fall for, even for savvy Web3 users.
For businesses, the potential impact of wallet drainers extends beyond the immediate financial loss.
While a single incident may not spell disaster, it can lead to reputational challenges over time if such vulnerabilities are not addressed.
Users expect security as a baseline, and incidents of wallet-draining can raise concerns about platform safety.
Addressing these concerns proactively helps maintain user trust and ensures a stronger foundation for growth.
A step-by-step look inside a wallet drainer attack
To fully understand how a drainer works, let’s walk through an example of a malicious dApp caught and flagged by Blockaid’s security platform.
The following breakdown was conducted in Blockaid’s Sandbox environment, a secure testing space where researchers can analyze the behavior of malicious dApps without compromising any real assets.
None of the transactions shown here were signed or executed onchain, ensuring that no actual funds were at risk. We are using this randomly chosen address as our fake address in this interaction.
This technical walk-through will help you see how wallet drainers operate behind the scenes, from the moment the user interacts with a malicious dApp to the final draining of assets.
Step 1: Crafting and distributing the malicious dApp
The first step in any wallet drainer attack is creating a malicious dApp that looks like a legitimate service.
These dApps are typically designed to mimic trusted platforms or exciting new projects, making them difficult to spot at first glance.
Attackers rely on crafting sites that trigger FOMO (Fear of Missing Out) to lure users in with promises of exclusive giveaways, airdrops, or rewards.
But the malicious dApp alone isn't enough—the real trick lies in how it's distributed. Attackers use a variety of methods to get users to visit these dApps:
- Spam ads on social media: Platforms like Twitter and Reddit are frequently flooded with fake airdrop promotions.
- Phishing emails and DMs: Users often receive enticing messages claiming to offer huge rewards in exchange for connecting their wallets.
- Frontend hijacking: In more sophisticated attacks, hackers compromise legitimate websites—like DeFi platforms—and replace their front end with a malicious version, seamlessly diverting users to the drainer.
Step 2: Getting the user to connect
Below is a malicious dApp disguised as a BNB Chain airdrop.
The site claims to allow users to check their eligibility for an upcoming airdrop, playing directly into users' FOMO.
Everything about the site was designed to rush users into connecting their wallets without raising too many suspicions.
No matter what button you click—whether it’s "Check Eligibility", “Learn More”, or even one of the fake blog posts —the “Connect Wallet” dialog pops up immediately.
This relentless prompt is a classic hallmark of an impersonating dApp, designed to rush users into giving access without a second thought.
Step 3: Extracting wallet information and preparing the attack
Once the user connects their wallet, the drainer immediately communicates with its Command and Control (C2) servers—the backend infrastructure that powers the attack.
These servers collect crucial data from the frontend dApp, such as the wallet’s address, token balances, and available assets.
Based on this information, the C2 servers instruct the frontend on what type of attack to execute. This could involve targeting specific tokens or initiating certain transactions to drain assets.
To make things harder for security researchers, the communication between the frontend and C2 is encrypted. While it's technically possible to reverse-engineer this process, it’s out of scope for this post.
Once this step is complete, the drainer is ready to move into the next phase: directly interacting with the blockchain to start draining assets.
Step 4: Onchain preparations
After receiving instructions from the C2 servers, the drainer begins performing onchain interactions.
To fully understand what the drainer is doing, we can analyze the JSON-RPC calls it sends to the wallet.
JSON-RPC is the communication protocol that enables requests between the dApp, the wallet, and the node. It’s how the dApp queries information, sends transactions, and interacts with smart contracts.
By examining these calls using the Blockaid sandbox environment, we can trace the drainer’s actions without executing any actual transactions or risking real assets.
One of the first JSON-RPC calls we observed was the wallet_switchEthereumChain
method, which forces the user’s wallet to switch to Arbitrum One:
{
"method": "wallet_switchEthereumChain",
"params": [
{
"chainId": "0xa4b1"
}
]
}
Even though the dApp posed as a BNB Chain airdrop, this switch to a different chain is a big red flag. It’s a classic trick used to target assets on another network that might hold more value or be easier to exploit.
Now, with the wallet on Arbitrum, the drainer starts issuing eth_call
JSON-RPC requests.
eth_call
is a JSON-RPC method used to read data from onchain contracts. In these calls, the to
field specifies which contract the data will be read from, and the parameters of the call are encoded in the data
argument—often referred to as the calldata.
To understand which function is being called, we can decode this calldata. Multiple tools, like Arbiscan’s Input Data Decoder, can be used to break down the data
field, revealing the specific function and parameters being invoked.
Let’s look at how the drainer uses eth_call
to gather data. Here’s the first eth_call
:
{
"method": "eth_call",
"params": [
{
"from": "0xffd65c58f7236989442d4b3fabbfc4e36ea0d051",
"to": "0x912ce59144191c1204e64559fe8253a0e49e6548",
"data": "0x7ecebe00000000000000000000000000ffd65c58f7236989442d4b3fabbfc4e36ea0d051"
},
"latest"
]
}
When we decode this call, we find that the drainer is calling the nonces(address)
function:
{
"function": "nonces(address)",
"params": [
"0xFfD65C58F7236989442d4b3faBbFC4e36EA0D051"
]
}
The drainer then issues another eth_call
to gather more information:
{
"method": "eth_call",
"params": [
{
"from": "0xffd65c58f7236989442d4b3fabbfc4e36ea0d051",
"to": "0x912ce59144191c1204e64559fe8253a0e49e6548",
"data": "0x06fdde03"
},
"latest"
]
}
Which decodes to:
{
"function": "name()",
"params": []
}
This retrieves the contract’s name, in this case, "Arbitrum."
Putting these two eth_call
requests together, we can see that the drainer is querying the contract for the wallet’s nonces and the contract’s name.
This information is essential for EIP-2612 (which the Arbitrum token follows), an ERC-20 extension that allows token approvals via off-chain signatures, also known as permits.
Step 5: Permit farming attack
By leveraging EIP-2612, the drainer is able to create a signature that authorizes asset transfers without the user explicitly approving the transaction onchain.
In the eth_call
we’ve observed, the drainer is collecting the data needed to craft their malicious permit transaction.
With the nonce and contract name in hand, the drainer has everything it needs - and can issue the transaction using the eth_signTypedData_v4
JSON-RPC method (which signs a structured piece of data, according to EIP-712 standards):
{
"method": "eth_signTypedData_v4",
"params": [
"0xffd65c58f7236989442d4b3fabbfc4e36ea0d051",
"{\"types\":{\"Permit\":[{\"name\":\"owner\",\"type\":\"address\"},{\"name\":\"spender\",\"type\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\"},{\"name\":\"nonce\",\"type\":\"uint256\"},{\"name\":\"deadline\",\"type\":\"uint256\"}],\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}]},\"domain\":{\"name\":\"Arbitrum\",\"version\":\"1\",\"chainId\":\"42161\",\"verifyingContract\":\"0x912ce59144191c1204e64559fe8253a0e49e6548\"},\"primaryType\":\"Permit\",\"message\":{\"owner\":\"0xffd65c58f7236989442d4b3fabbfc4e36ea0d051\",\"spender\":\"0x1618f13dac2f11a7fb8eec7e53f75671d116e93d\",\"value\":\"1158472395435294898592384258348512586931256000000000000000000\",\"nonce\":\"0\",\"deadline\":\"1758102346951\"}}"
]
}
This eth_signTypedData_v4
call constructs a permit message using the nonce (which ensures the transaction is unique and in sequence) and the name of the contract ("Arbitrum").
The permit authorizes the spender (in this case, the attacker’s address) to transfer a massive amount of tokens from the user’s wallet.
This permit is the final objective of all the preceding transactions. It gives the attacker full control to drain the victim’s ARB tokens. The drainer will then issue similar requests to drain any other tokens the user holds. Remember - Each signed transaction means another token drained.
Why this works: EIP-2612 and offchain signatures
In the traditional ERC-20 setup, granting approval is an onchain transaction. Once the approval is set, any authorized spender can use transferFrom
without further user interaction. Wallets can simulate these onchain transactions, providing users with a clear preview of what they’re authorizing.
EIP-2612 changes the game by replacing onchain approval transactions with an off-chain signature. Since it’s not a transaction, most wallets can’t simulate it—Blockaid is currently the only solution capable of generically simulating off-chain signatures.
This lack of simulation means that users often don’t realize they’re authorizing a transfer; they believe they’re simply signing a message, which appears less risky.
Once they have the signed message, attackers can submit it onchain through the token’s permit
function, granting themselves approval for transfers. This makes EIP-2612 permits a potent tool for wallet drainers, allowing them to avoid the scrutiny that onchain transactions would typically trigger.
Step 6: Native drain
With the permit attack executed and the assets approved for transfer, the drainer shifts focus to draining native tokens from the wallet.
Normally, sending ETH from one address to another is simple.
A dApp can initiate a straightforward transaction, moving ETH from one externally owned account (EOA) to another, with no calldata involved.
Here’s an example of what this kind of transaction might look like:
{
"method": "eth_sendTransaction",
"params": [
"from": "0xffd65c58f7236989442d4b3fabbfc4e36ea0d051",
"to": "0x912ce59144191c1204e64559fe8253a0e49e6548",
"value": "0xde0b6b3a7640000" // equivalent to 1 ETH
]
}
However, to avoid detection, the drainer uses a more sophisticated technique to mask their activity.
Instead of sending ETH directly to an attacker-controlled address, the drainer routes the transaction through a middleware—in this case, the legitimate SushiSwap Router contract.
Here’s what the actual transaction the drainer sent looks like:
{
"method": "eth_sendTransaction",
"params": [
{
"gas": "0x2fc88",
"gasPrice": "0x4116f4338",
"nonce": "0x4b",
"value": "0x814dbefd24822f08",
"from": "0xffd65c58f7236989442d4b3fabbfc4e36ea0d051",
"to": "0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f",
"data": "0xfb3bdb4100000000000000000000000000000000000000000000000000000005a53cb27800000000000000000000000000000000000000000000000000000000000000800000000000000000000000000e01b8ca4bfbb9712bd15be83a8d983c55556d7c000000000000000000000000000000000000000000000000000000006c1a37eb0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
}
]
}
The target contract (0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f
) is the legitimate SushiSwap Router contract. By decoding the calldata, we can see that this transaction calls the swapETHForExactTokens
function:
Reading through the SushiSwap documentation, we can see that this function allows the caller to swap ETH for a specified amount of another token, following a pre-defined path of tokens:
In this case, the path
parameter reveals that the drainer is swapping between WETH (Wrapped ETH, contract: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
) and USDC (USD Coin, contract: 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
).
By routing the transaction through a legitimate contract like SushiSwap, the drainer obfuscates the true intent of the transaction.
Rather than directly transferring ETH to an unknown address, which could easily raise suspicions, the transaction looks like a routine token swap.
This makes the attack harder to detect, as it appears to be a typical trade rather than a drain. Additionally, some security vendors automatically allowlist interactions with popular contracts like SushiSwap, adding an additional layer of complexity for detection.
Recap
Wallet drainers are malicious pieces of code designed to steal users' assets by tricking them into granting access to their wallets.
As Web3 grows, these attacks have become more sophisticated, making it crucial for companies to understand how they work to protect both users and their brand’s integrity.
In this example, the drainer executed several key steps:
- Fake Airdrop: The attack starts by posing as a legitimate airdrop, creating urgency (often through FOMO) to lure users in.
- User Connection: The dApp pushes the user to connect their wallet, giving the drainer access.
- C2 Communication: The drainer communicates with its C2 servers to gather critical wallet data and issue
eth_calls
to query for details like nonces and token balances. - Permit Farming: Using this data, the drainer exploits EIP-2612, crafting a malicious permit transaction that authorizes token transfers without user approval.
- Native Currency Drain via DEX: After draining tokens, the drainer targets the user’s native currency (e.g., ETH) and disguises the theft as a legitimate token swap through a DEX like SushiSwap.
Wallet drainers aren’t just a threat to user funds—they’re a threat to the trust your platform relies on.
Attackers are using increasingly sophisticated tactics, leveraging legitimate infrastructure to hide their intent and make detection harder than ever.
If companies fail to understand and defend against these attacks, the result is not just financial loss—it’s a loss of reputation, trust, and long-term user confidence.
Understanding these threats is no longer optional—it's essential. The stakes are high, and without the right defenses, your platform could be next.
Keep your users safe from drains
Blockaid’s Web3 security platform combines proactive threat hunting, real-time monitoring, and advanced transaction validation to protect your platform with a multi-layered defense against evolving threats.