October 20, 2026
|
Exploit Postmortem
Cover image for "Vestaa's $7.8K Loss and How Olympix Would Have Prevented It"

Vestaa's $7.8K Loss and How Olympix Would Have Prevented It

Date: October 10, 2026

Chain: Base

Loss: 3.1924 WETH, about $7.8K

Class: a Permit2 signature left valid and public after a failed transaction

At 21:42:15 UTC on October 10, 2026, a transaction from Vestaa's own wallet to its swap contract on Base failed. Failing should have been the end of it, but the transaction's input carried a Permit2 signature authorizing a transfer of WETH from Vestaa's own wallet, and a revert doesn't erase what a transaction sent. Anyone reading the chain could still see the signature, and because the transfer never happened, the signature was still good.

In the very next block, two seconds later, a searcher known as c0ffeebabe reused that signature and pulled 3.1924 WETH, about $7,800, out of Vestaa's wallet. Vestaa said so itself in an on-chain message to the searcher, which Defimon's alert relayed the next day: it traced the leak to a bug in its swap contract, said it had shut the affected system down, and asked for the funds back.

How Permit2 Signatures Work

Permit2 is Uniswap's shared approval contract, used by many swap contracts to move tokens with an off-chain signature instead of a separate on-chain approval. In its SignatureTransfer mode, a token holder signs a message that allows one transfer of a set token and amount, tagged with a nonce, a one-time number. When Permit2 executes the transfer it marks that nonce as used, so the same signature can't move funds twice. The Permit2 documentation describes the nonce as what makes each signature single-use.

That protection only kicks in when the transfer goes through. If the transaction carrying the signature reverts at any point, every state change in it is rolled back, including the nonce being marked as used. The signature goes back to being unused, and it's sitting in the failed transaction's public input data until its deadline passes.

A Replay One Block Later

Vestaa's message describes the sequence in two steps. A bug in its swap contract caused its own transaction, 0x27b2...29ab in Base block 52439594, to fail while carrying a valid Permit2 signature for its WETH, which left the signature exposed on-chain and unspent. One block later, c0ffeebabe.eth sent transaction 0x59c5...e885, which reused it. That transaction went to c0ffeebabe's contract at 0x16e4...7b19, and its logs on Base show 3.1924 WETH moving from Vestaa's wallet, 0x616d...1264, into 0x1d90...02e4, the same contract its failed transaction had called, and on through one more contract to c0ffeebabe's contract, which unwrapped it to ETH, while Vestaa's wallet received 0.000001 USDC in return. The two blocks are stamped two seconds apart, so the signature was in a stranger's hands within seconds of the failure.

Neither the message nor any public post names the line in the swap contract that caused the failure, and as of October 19, 2026, Vestaa hadn't published a post-mortem.

The teaching moment is that a signed authorization is live until it's consumed, and a transaction that fails hasn't consumed anything. Any contract that carries a signature in its call data has to treat the failure path as carefully as the success path. It's like handing a signed check to a cashier who drops it on the counter when the register jams: the check is still valid, and anyone standing nearby can pick it up.

Where It Stands

Vestaa shut down the affected system after the replay and asked publicly for the 3.1924 WETH to be returned, inviting c0ffeebabe to keep whatever portion it considered an appropriate bounty. As of October 19, 2026, no return had been reported publicly.

How Olympix Follows a Signature Down the Failure Path

Olympix reads a contract the way an attacker does, as states, transitions and entry points, and it takes in the context around the code, such as which external contracts it trusts with approvals, to infer the invariants the system relies on but never writes down. For a swap contract built on Permit2 SignatureTransfer, the invariant is one sentence: every signed authorization the contract handles must end up either used for its intended transfer or invalidated, and never left valid after a call fails.

A contract's state space looks infinite, but it isn't. The engine maps every path and uses signals to choose which ones to attack. The signal here is a Permit2 signature passed into a function that can revert before the transfer completes, with no step that invalidates the nonce on that path. Olympix's static analysis can plausibly surface that pattern, narrowing the search from all paths to the reverting ones that carry a live signature.

BugPoCer would take that rule as the thing to break. Counterexample-Guided Invariant Refutation starts from what the swap contract promises about every signature it touches and executes paths, the reverting ones included, until a signature survives a failed call and moves funds later. The engine's other method, Bounded Adversarial Verification in BugScout, starts at the flagged signal and tries known replay strategies against it, and the two share the engine's symbolic execution. For Vestaa, the counterexample BugPoCer would plausibly return is two transactions, a swap call that reverts with the signature still unspent and a second call from an unrelated address that reuses it to move the WETH, along with the minimal conditions that trigger it and a generated Forge test that replays it. That's the October 10 replay produced in development instead of on Base.

Olympix runs automatically in development, at every merge and before release, so a change that adds a new revert condition to a function holding a signature gets checked against the same rule.

Failure Paths Carry Signatures Too

Vestaa's loss was small, and the lesson scales to any contract that accepts signed approvals: a failed transaction leaves its inputs public and its state unchanged, so a signature that didn't get spent is still a working key. To see how Olympix traces your own signature flows through their failure paths, book a technical walkthrough.

On-Chain References

Protocol: Vestaa

Chain: Base

Date: October 10, 2026, 21:42:17 UTC

Loss: 3.1924 WETH (about $7,800)

Vestaa wallet (drained): 0x616d...1264

Swap contract called in both transactions: 0x1d90...02e4

Failed tx that exposed the signature (block 52439594): 0x27b2...29ab

Replay tx: 0x59c5...e885

Block: 52439595

c0ffeebabe.eth: 0xc0ff...9671

c0ffeebabe contract: 0x16e4...7b19

Sources

Defimon Alerts: Vestaa's on-chain message to c0ffeebabe, relayed on X

Uniswap: Permit2 SignatureTransfer reference

More from Olympix:

No items found.

Ready to Shift Security Assurance In-House? Talk to Our Security Experts Today.