Identified and demonstrated a critical exception-handling flaw in a major ERC-20 wallet provider. By sending a real ERC-20 transfer with an artificially low gas fee, the wallet showed the amount as received before the transaction confirmed — then a drop-and-replace attack silently cancelled it, yet the wallet still marked it as confirmed. Disclosed responsibly.
ERC-20 transfers on Ethereum require a gas fee — the higher the fee, the faster miners pick up the transaction. By sending a legitimate ERC-20 transfer via Web3 APIs with an artificially low gas price, the transaction entered the mempool but took an extremely long time to actually be mined and confirmed.
The wallet provider's critical mistake: it displayed the pending amount in the recipient's balance immediately — before the transaction was confirmed. To the recipient, the funds had arrived. In reality, the transaction could still fail, be stuck, or be replaced.
Ethereum transactions include a nonce — a
sequential counter per sender. Broadcasting a second transaction with the same nonce but a higher
gas fee causes miners to drop the original and process the replacement instead. This is the
standard "replace-by-fee" (RBF) mechanism.
By sending the replacement transaction — a tiny or zero-value transfer — the large original was silently cancelled on-chain. The wallet provider did not handle this exception. Instead of updating the status to "Dropped" or "Replaced", it left the original transaction marked as confirmed. The recipient's wallet showed the full amount as successfully received. The funds were never transferred.
The wallet credited the recipient's displayed balance as soon as a pending ERC-20 transfer was detected in the mempool — before any on-chain confirmation. This is the first and fundamental flaw that makes the attack possible.
When the original transaction was replaced via a higher-gas same-nonce broadcast, the
wallet's transaction status listener did not catch the replaced
or dropped state — leaving the original shown as "Confirmed".
① Send large ERC-20 tx with very low gas → ② Recipient's wallet shows funds as arrived → ③ Broadcast same-nonce tx with high gas for tiny amount → ④ Original is dropped on-chain, wallet shows it as confirmed anyway.
Full PoC written in Web3.js — both transactions scripted, reproducible on mainnet. Full technical report sent to the provider's security team. No public disclosure until patched — 18 days after report.