# Attacker can steal JackpotTicketNFT’s from JackpotBridgeManager.sol

JackpotBridgeManager's _bridgeFunds makes an arbitrary external call to user-supplied target, letting an attacker safeTransferFrom a victim's custodied JackpotTicketNFT to themselves.

- Payout: Contest reward
- Severity: high
- Program: Megapot
- Credited: 0xG0P1
- Disclosed: 2026-01-05
- Write-up quality: 7/10
- Original: https://code4rena.com/reports/2025-11-megapot#h-01
- Library page: https://bugbountylibrary.com/r/c4%3A2025-11-megapot%3AH-01
- Tags: domain:web3 impact:funds-loss impact:integrity kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:chained technique:source-review vuln:access-control vuln:business-logic

**Target:** JackpotBridgeManager.sol _bridgeFunds external call
**Root cause:** _bridgeFunds executes _bridgeDetails.to.call(_bridgeDetails.data) with fully user-controlled target and calldata, and the only post-check is a USDC balance delta that the attacker can satisfy via the approveTo allowance.
**Steps:**
1. Attacker buys tickets via buyTickets so JackpotBridgeManager custodies NFTs and attacker has claimable tickets.
2. After draw, attacker builds RelayTxData: approveTo=exploit contract, to=jackpotNFT, data=safeTransferFrom(bridgeManager, exploit, victimTokenId, '0x').
3. Attacker calls claimWinnings(attackerTicketIds, maliciousBridgeDetails, signature).
4. _bridgeFunds approves exploit for _claimedAmount, then calls jackpotNFT.safeTransferFrom, moving victim NFT to exploit.
5. Exploit's onERC721Received pulls the approved USDC via transferFrom so pre-post balance equals _claimedAmount, passing NotAllFundsBridged check.
**How found:** Code review of _bridgeFunds: noticed _bridgeDetails.to and .data are user-controlled and the only guard is a USDC balance delta, which is satisfiable via the approveTo allowance during the callback.
**Exploitation:** Attacker needs a valid claim (own winning tickets) and a victim NFT custodied by the bridge. The approveTo allowance is set to the exploit contract before the arbitrary call; the ERC721 receive hook drains exactly _claimedAmount USDC to satisfy the balance check while the victim NFT is transferred out.
**Insight:** When a contract both approves an attacker-chosen spender and then makes an attacker-chosen external call, the balance-delta invariant can be satisfied inside the callback — look for approve-then-arbitrary-call patterns where the post-check is a token balance rather than a whitelisted target.
