On 2026-08-22, an attacker on Base hijacked the SAND OFT's LayerZero delegate role through `approveAndCall`, minted 10,000,000 unbacked SAND per tx, and ran ~400+ txs of an ongoing campaign totalling roughly $49B face value at report time.
Logged as “2026-08-22: Layerzero Delegate Hijack Via Approveandcall on SandboxOFT”.
The OFTSand contract at 0xac531Eb26Ca1d21b85126De8FB87E80E09002DcF (the SAND OFT on Base) exposes an ERC677-style helper approveAndCall(target, amount, data) that does target.call{value: msg.value}(data) with msg.sender set to the token itself. Its only guard is doFirstParamEqualsAddress(data, _msgSender()), that the first 32-byte word of data equals the caller. The guard is meant to stop spending someone else's approval, but it does nothing to constrain which function the token is made to call. The helper is a generic "call any contract AS the token" primitive reachable by any address.
The token is the OApp registered in LayerZero EndpointV2 at 0x1a44076050125825900e736c501f859c50fE728c. The attacker (EOA 0x638Ccb18370eE228378a565c1d4D0F9620d7F296, attack contract 0xd7Cb71EE00a812FC22ACcfE08A2f59A5Add2f6Ca) called approveAndCall(Endpoint, 0, setDelegate(attacker)). The first parameter of setDelegate(address) is the attacker itself, equal to addr, so the guard passed, and the token executed Endpoint.setDelegate(attacker) with msg.sender set to the token, hijacking the OApp's delegate role.
As delegate, the attacker reconfigured the OApp's receive stack. First Endpoint.setConfig(OFTSand, ReceiveUln302, UlnConfig{requiredDVNs:[attacker]}), replacing the inbound DVNs with the attacker's own contract for srcEid 30101. Then ReceiveUln302.verify(header, payloadHash, 1) as that DVN, self-attesting a forged inbound packet whose peer[30101] is the OFT's own address (SAND OFT is deployed at the same address on Ethereum and Base, so the sender field passes the OApp peer check). Then ReceiveUln302.commitVerification(header, payloadHash) to commit it to the Endpoint. Finally Endpoint.lzReceive(origin, OFTSand, guid, message, "") to deliver the forged packet. OFTSand._credit does a bare _mint(to, amountLD). Unbacked SAND appears.
The attacker minted 10,000,000 SAND per transaction (amountSD 1e13 times decimalConversionRate 1e12), per the exploit transaction 0x76ed03844ff61520a0fb99278f92f2f1453b24ccbacd20b91131703e4a56a446 on Base block 50,289,412. The PoC records the face value of one representative tx at ~$517,170, while the campaign had minted ~$49B face value across 400+ transactions in an ongoing series at report time.
The fix is to remove approveAndCall's "first parameter must equal caller" check entirely (it guards no caller) or to constrain approveAndCall to a whitelist of approved target addresses and selectors. The deeper fix is for LayerZero endpoints to record the OApp's own address in the DVN-required list and to ignore DVNs registered by a delegate that was not authorised by the OApp's setDelegate() directly (the token contract should not be a valid setDelegate caller for itself).
Query every incident yourself — free, no signup
Updated 14 Oct 2026. Figures are as reported by the sources listed above and are not independently verified.