JaredFromSubway’s MEV bot lost $7.5M to an approval trap. A smarter bot wasn’t the fix.
The JaredFromSubway.eth sandwich bot was drained of $7.5M after attackers tricked it into granting ERC-20 approvals to malicious helper contracts. How 1Claw’s intent-based signing, deny-by-default permits, allowlists, and mandatory simulation stop approval-trap exploits.
On June 20, 2026, the most famous sandwich bot on Ethereum, JaredFromSubway.eth, got drained of more than $7.5 million in WETH, USDC, and USDT. No reentrancy bug. No oracle manipulation. No leaked private key. The attacker spent weeks feeding the bot fake trades that looked profitable, until the bot handed out ERC-20 token approvals to contracts the attacker controlled. After that, draining it was just a few transferFrom calls.
A bot that got rich front-running other people's trades lost to a counter-strategy that used its own automation against it. And the lesson is one we keep watching teams learn the hard way in 2026: the thing that drains you isn't always a broken contract. Sometimes it's an automated signer approving things it never should have.
How the approval trap worked
The attacker deployed dozens of fake token contracts and liquidity pools dressed up to look like wrapped Ether and the big stablecoins. To the bot's pattern-matching, these were fresh, profitable opportunities. So it did exactly what it was built to do. It traded against them, and somewhere in that "routine" execution it approved helper contracts it had never checked.
At first the approvals got consumed right away, so nothing looked off. Later runs left standing allowances sitting there. One of them gave a helper contract at 0x4ee0…313ce the right to spend about 92 WETH, and it was never revoked. Once the trap was set, the attacker called transferFromfrom a sweep contract, pulled the funds straight out of the bot's wallets into 0x3e37…65d0, and ran some of it through Tornado Cash. The operator has since offered a 50% white-hat bounty for 2,150 ETH back. As of writing, nothing has been returned.
The real bug was nothing standing between "decide" and "approve"
Token approvals are one of the most overlooked attack surfaces in DeFi. An approve, or a gasless Permit / Permit2signature, doesn't move money on its own. It quietly hands someone else the right to move your money later. If a bot can mint approvals to whatever contract it decides looks profitable, then your whole wallet rides on it never getting fooled. JaredFromSubway got fooled.
It's the same shape of failure we see in drained treasuries and rogue AI agents:
- The code that decides what to do is also the code that holds the key and signs.
- Approvals and transfers go wherever the logic points them. No allowlist, no boundary a human set.
- No simulation step that says "hold on, this grants spend rights to a contract nobody has seen."
- No cleanup, so one leftover approval sits around as a time bomb.
You don't fix this with a smarter model or a cleverer heuristic. As long as the bot can be talked into signing, it can be drained. The fix is structural. Pull the signer apart from the brain, and make the signer boring: strict, narrow, and deny-by-default.
How 1Claw breaks this attack
1Claw is built on one rule: the thing that signs shouldn't be the thing that thinks. Your bot submits an intent. Vault, or Shroud's signer running in a TEE, checks that intent against your policy and only then produces a signature. The key never enters the bot's process. For an approval trap like this one, that gives you four checks, and the attacker has to beat all of them.
1. Approvals and permits are denied by default
1Claw's sign endpoint treats approval-style signatures as dangerous out of the box. For EIP-712 typed data the default policy is deny unless you opt in, and the risky types (Permit, Permit2, DaiPermit, PermitSingle, PermitBatch) always need an explicit allowlist, checked against the verifyingContract. A gasless permit to some attacker's fake-WETH contract gets rejected before any signature exists.
await client.agents.update(agentId, {
// Permits are denied unless the verifying contract is on the list
eip712_default_policy: "deny",
eip712_domain_allowlist: [
{ verifying_contract: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" }, // canonical WETH
{ verifying_contract: "0xKnownRouter" },
],
});2. Allowlists and spend caps on every transaction
For on-chain transactions, the Intents API runs per-agent guardrails on the server before the HSM ever unwraps a signing key. You pick the addresses the agent is allowed to touch, a hard cap on any single transaction, and a rolling 24-hour spend limit. So even if a fake pool sneaks past everything else, the damage is capped. The attacker can't empty the wallet, because the daily limit and the allowlist won't let the sweep through.
await client.agents.update(agentId, {
intents_api_enabled: true,
tx_to_allowlist: ["0xYourTreasury", "0xKnownRouter"],
tx_max_value_eth: "0.5",
tx_daily_limit_eth: "2.0",
tx_allowed_chains: ["ethereum", "base"],
});Flip on intents_api_enabled and direct reads of private_keysecrets start returning 403. The bot has to sign through the proxy. There's no raw key sitting in the process for a compromised loop to walk off with.
3. Simulate before you sign
This is the check made for this exact exploit. Turn on simulate_first (or the org-wide require_simulation setting) and 1Claw runs the transaction through Tenderly before it signs anything. The result shows you the balance changes and approvals. A transaction granting 92 WETH of allowance to some unknown helper shows up as an approval change to an address that isn't on your list. A reverted or disallowed simulation records the attempt and returns 422 instead of signing.
const tx = await client.agents.submitTransaction(agentId, {
chain: "ethereum",
to: "0xKnownRouter",
data: swapCalldata,
simulate_first: true, // reverts or disallowed flows return 422, no signature
});4. The TEE reads the call arguments
Shroud, our TEE-backed proxy, adds tool-call inspection. It reads the arguments of a function or transaction before the bot can fire off something dangerous. An approve(spender, amount) where the spenderisn't a contract you've allowlisted is exactly the kind of thing it flags. And when the signing runs through Shroud, the key stays inside the enclave the whole time.
Why it takes all four
The drain worked because there was one straight, unguarded line from "the bot thinks this is profitable" to "the chain accepted a transferable approval." 1Claw cuts that line into pieces an attacker would have to break at the same time. The permit is denied by default. The destination isn't on the allowlist. Simulation catches the approval. The daily cap limits the bleeding. The key never leaves the HSM or the TEE. That's the gap between a logged, rejected intent and a $7.5 million headline.
If you run a bot, do this
- Go look at every standing token approval your bots and treasury wallets have out there. Revoke anything pointed at a contract you can't name.
- Put signing behind an intent layer so the trading logic asks to sign instead of holding the key. Start with one agent on the Intents API.
- Set an address allowlist, a per-transaction cap, and a daily limit before the agent ever touches real money.
- Deny approvals and permits by default, and allowlist the verifying contracts you actually use.
- Require simulation on anything that can grant an allowance, and run argument-bearing calls through Shroud.
MEV bots live and die on speed, and that's exactly why they skip the guardrails that would have saved this one. You don't actually have to choose. Intent-based signing, allowlists, and simulation cost milliseconds. The unverified approval cost JaredFromSubway $7.5 million.
Get started for free · Intents API guide · EVM signing & EIP-712 guardrails