Drained MEV Bot: No-Auth Transfers and Unsafe msg.sender.call

BSC • Address: 0xAD94…0449

Published on June 12, 2025

Abstract

A frantic builder pinged us after their MEV bot was wiped. Decompiling the bytecode told the story: wide-open msg.sender.call() calls and token transfers that trusted whoever knocked on the door. Together they let an attacker empty both ETH and tokens in a single sweep — a textbook reminder that speed without guardrails is costly.

We pulled the drained bot into EVMDecompiler and stepped through the reconstructed callbacks. The bytecode (no published source) made two facepalm-level mistakes:

Decompiled fragments

function d3MMSwapCallback(address _token, uint256 _amount, bytes calldata) external {
    IERC20(_token).transfer(msg.sender, _amount);
}

function swapX2YCallback(uint256 amountX, uint256, bytes calldata data) external {
    require(amountX <= 0 || amountX == 0);
    (bool success, bytes memory result) = msg.sender.call{value: amountX}("");
    require(success, "SwapX2Y: ERC20 operation did not succeed");
}

function swapCallback(uint256 amount0, uint256 amount1, bytes calldata data) external override {
    _swapCallback(msg.sender, amount0, amount1, data);
}

Why this is fatal

Safer patterns

Analysis comes straight from the decompiled bytecode; we renamed functions so the narrative is easier to follow.