
Date: September 24 to 25, 2026
Chain: Ethereum, with Payment Processor V3 on ApeChain affected by the same bug
Loss: about $3.4M net in WETH, other tokens and NFTs, including 660 WETH (about $1.7M), with 23,155 NFTs rescued in the first night
Class: trade authorization based on a sender identity that could be forged
At 13:07:59 UTC on September 24, 2026, an Ethereum wallet deployed a contract and, in the same transaction, moved 10 Meebits, 50 Otherdeeds and 10 World of Women NFTs out of a single collector's wallet, each one routed through Limit Break's Payment Processor V2. What made that possible was an approval: in 2024, Magic Eden users granted Payment Processor V2 permission to move their NFTs and tokens so it could settle their trades.
Magic Eden stopped using Payment Processor V2 in October 2024 and closed its EVM marketplace in the first quarter of 2026, but approvals on Ethereum don't expire, and many of those wallets never revoked them. A white-hat effort moved 23,155 NFTs worth more than $5.7 million to safety overnight, but 660 WETH was gone before anyone could protect it, and Revoke.cash now puts the net loss at about $3.4 million once stolen NFTs and later returns are counted. Researcher 0xQuit's summary of the flaw is that the contract trusted an "original sender" passed in through a trusted forwarder, and that sender could be forged.
Payment Processor is Limit Break's NFT exchange protocol, built for its royalty-enforcing ERC-721-C and ERC-1155-C token standards and compatible with standard NFTs. In its September 25 update, Limit Break said V2 was integrated in collaboration with Reservoir and Magic Eden over months in 2023 and 2024. The Block reports that NFTs listed roughly between February and October 2024 were the ones at risk, and Magic Eden said no live listings were affected.
Blockscout shows how V2 is put together on Ethereum. The contract users approved, PaymentProcessor at 0x9A1D...6834, was deployed on February 2, 2024, and it's a router: it holds four immutable module addresses, for payment settings, on-chain cancellation, trades and advanced trades, and delegatecalls into them, so the module code runs with the router's address and the approvals pointing at it. The trades module, ModuleTrades at 0x9A1D...d7Dc, was deployed four minutes earlier the same day. Neither the router nor its modules can be upgraded or paused.
What mattered was the approval each user had granted, usually a setApprovalForAll, which lets a contract move every NFT in a collection on the owner's behalf, or an ERC-20 approval for tokens like WETH. Canceling old listings didn't help. Any wallet that still had an approval pointing at Payment Processor V2 was exposed for as long as the approval stayed in place.
Payment Processor V2 supports meta-transactions through trusted forwarders, a pattern standardized as ERC-2771. A forwarder contract submits a call on a user's behalf and appends that user's address as the last 20 bytes of the calldata, and the receiving contract reads those bytes as the real sender, but only after confirming the call came from a forwarder it trusts. The router's own comments describe it as designed to work both through direct calls and through a trusted forwarder that preserves the original sender by appending 20 bytes, and its delegatecall helpers pass those trailing bytes on to the module.
From the verified ModuleTrades source on Etherscan and Blockscout (src/modules/ModuleTrades.sol), this is how acceptOffer, the function a seller calls to accept a buyer's offer, works out who the seller is:
The first block measures how much calldata arrived beyond a normal acceptOffer call. BASE_MSG_LENGTH_ACCEPT_OFFER is 1,060 bytes in the verified constants file, and each Merkle proof element adds 32 more, so whatever is left over is treated as appended data. The TradeContext that follows sets the channel to msg.sender, the address that called the router, and sets the taker, which in acceptOffer is the seller whose NFT will move to the buyer. If exactly 20 extra bytes arrived, the taker comes from _msgSender(). Otherwise it's simply msg.sender.
_msgSender() lives in Limit Break's TrustedForwarderERC2771Context library, included in the same verified source:
The function asks Limit Break's TrustedForwarderFactory whether the caller is one of its forwarders. If it is, the assembly line reads the last 20 bytes of the calldata and returns them as the sender, and if not, it returns the real caller. Put together, the identity of the seller in a trade comes from the position of bytes at the end of the calldata, computed in the module from a length the router assembled, and trusted because the immediate caller is a registered forwarder. The same taker line appears in four entry points of the verified module: buyListing, acceptOffer, bulkBuyListings and bulkAcceptOffers, which covers both selling NFTs and paying for them.
0xQuit's account, quoted by NFT Culture, is that this original sender could be forged, so the contract could be made to believe a victim had accepted a trade. As of October 20, 2026, neither Limit Break nor Revoke.cash had published which bytes the attacker controlled or how, so this post describes the identity path the code uses and the published account of what went wrong, and doesn't reconstruct the exact forgery.
The lesson for builders is that a standing approval turns every identity check in the approved contract into the last line of defense for the user's whole wallet. When a contract works out who's asking from data that passes through several hands, the approval is only as strong as the weakest step in that chain. It's like a building that lets anyone in whose name is on a visitor slip, as long as the slip came through the front desk, without checking who wrote the name.
Blockscout's trace of the first transaction, 0x9050...93d3 in block 26,047,513, shows the path. The externally owned account 0x0e9E...d1c7 deployed a contract at 0x7400...6d8e, and that contract repeatedly called 0xb233...84C9, a forwarder clone that Limit Break's TrustedForwarderFactory created on February 6, 2024. Each time, the forwarder called Payment Processor V2, the router delegatecalled ModuleTrades, ModuleTrades asked the TrustedForwarderFactory whether the forwarder was trusted, and the NFT collection then moved a token from wallet 0xDDF2...5d38 to 0x0e9E...d1c7. The transaction carried 70 NFT transfers, all from that one wallet: 10 Meebits, 50 Otherdeed Expanded and 10 World of Women. Those match the first numbers 0xQuit posted, which also included 235 Desperate ApeWives taken in other transactions.
On-chain, the activity showed up as Payment Processor V2 settling trades at a price of zero. The Crypto Times logged a sample transaction, 0x1692...c926 in block 26,052,469, that emitted AcceptOfferERC721 events from V2 with a zero sale price and WETH as the payment coin. Revoke.cash describes the WETH side as the mirror image: attackers drained approved tokens by forcing wallets to buy worthless NFTs. 0xQuit wrote that it was more than 12 hours before anyone reported the first theft to him, and that once he dug in, he realized a great many NFTs were exposed to the same exploit.
The sample transaction The Crypto Times logged came from the rescue, and the white-hat wallet sent it at 05:46:47 UTC on September 25. At 06:31 UTC that morning, NFT researcher Cirrus reported that one wallet had pulled 3,832 NFTs from hundreds of wallets and warned holders to revoke their approvals. Sixteen minutes later, 0xQuit replied that the wallet belonged to a white hat and that its contents would be returned once they were no longer at risk. He contacted Limit Break, which paused Payment Processor V3, carrying the same bug, on every chain except ApeChain, where it couldn't be paused at the time. V2 couldn't be paused at all, so the only way to protect exposed assets was to move them first. That first rescue round put 23,155 NFTs into white-hat custody, and 0xQuit later found that the same flaw could be used in reverse against WETH, where 660 WETH was taken before the team could act.
Owners could reclaim rescued NFTs through nftsaresafu.xyz after revoking their Payment Processor approvals. Limit Break's update thanked 0xQuit and jiri123_eth, said V2 was immutable and couldn't be updated or patched by anyone, told users to revoke permissions to both V2 and V3, and said its investigation was ongoing. Magic Eden told users to revoke the V2 approval on Ethereum, Polygon and Base, and eGamers reports that OpenSea flagged more than 3,000 items as stolen and blocked them from trading.
Revoke.cash's tracker gives the fullest count as of October 20, 2026. Most thefts happened in the first two days, with smaller ones continuing for weeks. Attackers drained about 622 WETH and smaller amounts of other tokens, worth about $1.7M, and took NFTs worth at least $2.5M, mostly on Ethereum, Polygon and Base. Security researchers led by 0xQuit moved more than 200,000 NFTs into safekeeping across two rescue rounds, and owners have claimed back more than $4M worth. An arbitrage bot that front-ran the first WETH theft offered to return 90% of what it took, had paid back about 140 ETH by October and was holding over 100 ETH more for owners who hadn't claimed, and some attackers handed NFTs back, which leaves about $3.4M lost. V3 on ApeChain remains usable until November 30, 2026. As of October 20, the addresses behind the 660 WETH loss hadn't been published, and Limit Break's X account showed no post about the hack after its September 25 update.
Limit Break said V2's code had been audited multiple times by professional audit firms, and nothing published suggests otherwise. Audits review the code in scope at the time, against the threats the team and auditors expect, and V2 then stayed live and unchangeable for more than two and a half years while the marketplace that used it moved on. Its sender logic is split across three separately written pieces: a router that forwards trailing calldata, a module that infers from length whether a call was forwarded, and a library that trusts the last 20 bytes from any registered forwarder. The published account places the flaw in the forwarded original sender, which only exists where those three pieces meet.
Limit Break had already moved on in its design. It released Payment Processor V3 on November 18, 2024, adding the ability to pause trading and time-bound permissions that expire automatically. Those features limit how long an approval can be abused and give a team a way to stop it, and V2 had neither, which is why the response came down to white hats racing attackers for the same assets.
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 addresses users approve and which forwarders the contract trusts, to infer the invariants the system relies on but never writes down. For an exchange contract that holds standing approvals, the invariant is one sentence: an NFT or token should only leave an owner's wallet when that owner authorized that specific trade.
The signal in the quoted code is a trade party whose identity comes from calldata position rather than from msg.sender or a signature, with the decision to read that position made from a length check in one contract and the trust check made against a factory in another, on a path that ends in a transfer under someone else's approval. A contract's state space looks infinite, but it isn't. The engine maps every path into buyListing, acceptOffer and their bulk versions, keeps the feasible ones that reach a token transfer, and narrows those to the paths where the taker isn't the address that called, since those are the only ones that can move an asset without its owner calling.
Counterexample-Guided Invariant Refutation, the method BugPoCer runs, starts from the authorization rule and executes calls through the router, with and without a forwarder and with different calldata shapes, until one moves an asset whose owner never called or signed. Bounded Adversarial Verification, BugScout's method, starts from the signal and runs known sender-spoofing strategies against it, and both rely on the engine's symbolic execution. Based on the published description, the counterexample for this exploit would contain a wallet with a standing approval to the router, a call that reaches acceptOffer through a registered forwarder with a taker the contract resolves to that wallet, a zero-price offer, and the resulting transfer of the wallet's NFT, together with the minimal conditions that make the module treat the call as forwarded. Olympix returns that sequence with a generated Forge test that replays it and asserts the owner's balance dropped without the owner's call, and the same test pointed at buyListing would cover the WETH direction.
Olympix runs automatically in development, at every merge and before release. For an immutable contract, the merges before the February 2024 deployment were the only window in which a finding like this could change the code, and the test would have shown up there, before any user granted the first approval.
Payment Processor V2's users had moved on, and so had the marketplace that brought them there, but their approvals stayed live on a contract nobody could pause. Any team that ships a contract users will approve should assume those approvals will still be live long after the product is gone, and should test every path that decides whose assets move against the one rule that matters. To see how Olympix tests the authorization paths around your own approvals, book a technical walkthrough.
Protocol: Limit Break Payment Processor V2 (used by Magic Eden in 2024)
Chain: Ethereum (V3 on ApeChain affected by the same bug)
Date: September 24 to 25, 2026
Loss: about $3.4M net per Revoke.cash (roughly 622 WETH plus other tokens and at least $2.5M in NFTs, after some returns); 660 WETH (about $1.7M) unrecovered per 0xQuit; 23,155 NFTs rescued in the first round
Payment Processor V2 (Ethereum, deployed February 2, 2024): 0x9A1D...6834
ModuleTrades (V2 trades module): 0x9A1D...d7Dc
TrustedForwarderFactory: 0xFF00...8DcE
Forwarder clone used in the first exploit tx (created February 6, 2024): 0xb233...84C9
Payment Processor V3 (ApeChain, usable until November 30, 2026 per Revoke.cash): 0x9a1D...5366
First exploit tx (September 24, 13:07:59 UTC, block 26047513): 0x9050...93d3
Exploiter EOA, deployer and NFT recipient in that tx: 0x0e9E...d1c7
Attack contract created in that tx: 0x7400...6d8e
Victim wallet in that tx: 0xDDF2...5d38
White-hat rescue wallet: 0x71cF...fe33
Sample rescue tx: 0x1692...c926
Revoke.cash: 2026 Magic Eden / Limit Break Hack
0xQuit on X: Payment Processor V2 exploit and white-hat rescue
Limit Break on X: Payment Processor V2/V3 permissions hack update
The Block: Magic Eden legacy approvals leave $5.7 million in NFTs exposed to exploit before rescue
NFT Culture: PaymentProcessorV2 Exploit, 0xQuit Rescue Explained
The Crypto Times: Limit Break NFT Exploit, Quit Rescues 23,155 NFTs, Says 660 WETH Lost