# Sandbox SAND OFT: delegate hijack mints unbacked tokens

Sandbox SAND OFT's approveAndCall arbitrary-call-as-token primitive let attacker hijack LayerZero delegate, become sole DVN, and mint 10M unbacked SAND.

- Payout: Real-world hack
- Severity: critical
- Program: SandboxOFT
- Credited: DeFiHackLabs
- Disclosed: 2026-08-22
- Write-up quality: 9/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2026-08/SandboxOFT_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20260822-sandboxoft
- Tags: domain:web3 impact:funds-loss impact:integrity kind:incident platform:defihacklabs sev:critical tech:evm tech:solidity technique:chained technique:source-review vuln:access-control vuln:business-logic

**Target:** LayerZero OFT token (OFTSand) on Base
**Root cause:** OFTSand.approveAndCall executes target.call(data) as the token with only a first-param-equals-caller guard, allowing arbitrary function calls as the token; attacker used it to call Endpoint.setDelegate and hijack the OApp delegate role.
**Steps:**
1. Call `SAND.approveAndCall(Endpoint, 0, setDelegate(attacker))` — first param equals caller so guard passes, token becomes msg.sender to Endpoint
2. As delegate, call `Endpoint.setConfig(OFTSand, ReceiveUln302, UlnConfig{requiredDVNs:[attacker]})` for srcEid 30101
3. As the sole DVN, call `ReceiveUln302.verify(header, payloadHash, 1)` then `commitVerification(header, payloadHash)` with forged packet
4. Call `Endpoint.lzReceive(origin, OFTSand, guid, message, "")` with message encoding attacker as recipient and amountSD 1e13
5. OFTSand._credit mints 1e13 * 1e12 = 1e25 = 10,000,000 SAND to attacker
**How found:** Code reading of OFTSand.approveAndCall revealed the only guard is doFirstParamEqualsAddress(data, _msgSender()), which constrains the first argument but not the target function — turning it into a generic call-any-contract-as-token primitive; recognized the token is the OApp registered in EndpointV2, so setDelegate(address) with attacker as first param passes the guard.
**Exploitation:** Permissionless: any caller invokes approveAndCall to make the token call Endpoint.setDelegate(attacker), then reconfigures the receive stack to trust attacker's contract as sole DVN, self-attests a forged inbound packet from srcEid 30101 (peer check passes because SAND OFT shares address on Ethereum and Base), and delivers it via lzReceive to trigger unbacked _mint. Repeated across 400+ txs minting ~$49B face value.
**Escalation:** Campaign scaled to 400+ repeated txs minting ~$49B face value; single tx minted 10M SAND (~$517k).
**Insight:** ERC677-style approveAndCall helpers that only check the first calldata word against msg.sender are arbitrary-call-as-contract primitives — audit any such helper on tokens that hold privileged roles (OApp delegate, owner, minter) in external protocols.
