Step 1 — The lure
Drainers don't usually pop up out of nowhere. They arrive through a familiar door: a Twitter / X post pretending to be an NFT mint announcement, a Discord DM offering free tokens to "verify your wallet," a Google ad placed against a search for a well-known dApp, a copy-pasted Notion document spreading among a group of friends. The URL on the page is one or two characters off from a real one — metamash.io, uni-swap.org, opensaa.io.
TYPOSQUAT signal — fired before you've even clicked connect.Step 2 — Connect
You click "Connect wallet." Your wallet (MetaMask, Rabby, Phantom) shows a permission popup. You approve. Nothing alarming happens yet. The page now has read-only access to your address. The attacker uses that read access to do something interesting: they scan your wallet's holdings — every ERC-20, every NFT collection — and compute which assets are worth stealing. Drainers don't waste time on $5 of meme tokens. They target the wallet's biggest, most liquid positions.
Step 3 — The ask
Now the wallet popup re-appears with a request. Depending on the drainer family it'll be one of these three shapes:
3a — The unlimited approve
Classic and still the most common. The contract asks you to sign an ERC-20 approve(spender, amount) where amount is 2^256 - 1 — the largest value a 256-bit integer can hold.
Function: approve(address spender, uint256 amount)
spender: 0xDEADbeef… (attacker contract)
amount: ffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffff ← unlimited
If you sign this for a token, the attacker contract can then call transferFrom on that token at any time, forever, until you revoke. They wait a few minutes (you're probably still on the page reading) and drain that token entirely.
APPROVE_UNLIMITED signal. UTXO Guard decodes the call data on the fly, sees that the amount is ≥ 2160, and surfaces a critical banner. The wallet popup still appears — Guard doesn't block — but you've already been warned in plain language before clicking confirm.3b — The NFT-collection setApprovalForAll
For NFT holders, the equivalent attack is setApprovalForAll(operator, true). One signature grants the operator the right to transfer every NFT you own in that collection. The most common cover story: "verify you own this NFT to claim your airdrop." There is no airdrop.
UTXO Guard's NFT_APPROVE_ALL signal is hard-coded to critical. Genuine dApps use setApprovalForAll too (marketplaces need it), so the warning won't tell you not to sign — but it will make sure you understand what you're authorising.
3c — The off-chain Permit signature
The most elegant and the most dangerous of the three: off-chain Permit signatures (EIP-2612 Permit, EIP-712 Permit2, and Uniswap's PermitSingle). Instead of an on-chain approval, the dApp asks you to sign a piece of structured data. No gas is spent. Nothing shows up on Etherscan. To the average user it looks like "just signing a message."
But the signed data is an approval. It says: "Token X authorises spender Y to move value of my balance before deadline Z, on chain ID N." A drainer that holds your signed Permit can use it to drain you up to value with no further interaction from you. If value is set to the max uint256, it's identical in power to the on-chain unlimited approval — minus the visibility.
PERMIT_UNLIMITED signal is the one we're proudest of catching. The off-chain Permit-drainer family was specifically designed to be invisible to wallet history. Guard decodes the EIP-712 payload locally and flags any value above the unlimited threshold.Step 4 — The drain
Once you've signed, the attacker doesn't necessarily move immediately. They may queue your wallet alongside dozens or hundreds of victims, then drain in a coordinated batch at a time of day when their flashbot bundle is most likely to succeed. By the time you check the page again, the wallet is empty.
What Guard does
- Decodes the request before signing. Calldata, typed-data payload, signature type — all parsed in the page using the local SafeSign kernel.
- Scores it locally. 0-100 based on weighted signals. Score is shown alongside the plain-language list of what's risky.
- Banners high-risk requests. Critical and high requests trigger an in-page slide-down banner so you see it before you click the wallet popup.
- Never modifies the request. Guard is observe-only. The decision is always yours, in your wallet. We just make sure you actually understand what you're confirming.
What you can do without Guard
- Verify the domain character-by-character before connecting. Yes, one letter matters.
- When in doubt, paste the URL into a separate tab and check it doesn't redirect somewhere you don't expect.
- Treat off-chain signatures with the same suspicion as on-chain transactions.
- Use a separate burner wallet for new dApps. Keep your main wallet for known counter-parties only.
- Revoke old approvals quarterly via revoke.cash or your wallet's built-in revoker.