# LeverageSIR: storage slot collision enables vault drain

LeverageSIR vault's storage slot 1 was overwritten via a crafted token mint, letting attacker spoof the Uniswap callback and drain USDC, WBTC, WETH.

- Payout: Real-world hack
- Severity: critical
- Program: LeverageSIR
- Credited: DeFiHackLabs
- Disclosed: 2025-03-30
- Write-up quality: 8/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2025-03/LeverageSIR_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20250330-leveragesir
- Tags: domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:critical tech:evm tech:solidity technique:chained technique:source-review vuln:access-control vuln:accounting-error

**Target:** LeverageSIR vault contract on Ethereum mainnet
**Root cause:** Vault stored a critical address (the token/controller) in storage slot 1, which the attacker could overwrite by minting a malicious token whose balance/allowance mapping collided with slot 1, making the vault trust an attacker-controlled address as the Uniswap callback caller.
**Steps:**
1. Deploy two attacker contracts A and B; brute-force until address(A) < address(B) for CREATE2 ordering.
2. Create and initialize a Uniswap V3 pool for token B vs A at price 1:1.
3. Mint a large V3 position and swap to give contract A a huge balance of token B.
4. Call `vault.initialize(VaultParameters(address(attC_B), address(this), 0))` to set the vault's token to B.
5. Call `vault.mint(true, params, 139650998347915452795864661928406629, 1)` — this writes the huge amount into storage slot 1, which is the vault's stored callback/controller address.
6. Compute the CREATE2 salt so the deployed contract address equals the value now in slot 1 (`0x00000000001271551295307acc16ba1e7e0d4281`), and deploy it via the immutable CREATE2 factory.
7. From the deployed contract, call `vault.uniswapV3SwapCallback` with crafted data to make the vault transfer all USDC to the attacker contract.
8. Call the deployed contract again to transfer USDC to the attacker and re-manipulate slot 1 back to attacker contract A.
9. Call `vault.uniswapV3SwapCallback(0, wbtcBal, data3)` to drain all WBTC, then repeat for WETH.
**How found:** Likely identified that the vault's slot 1 held a security-critical address and that mint() wrote an attacker-influenced amount into that slot; then realized a CREATE2-deployed contract could be placed at the resulting numeric address to satisfy the callback check.
**Exploitation:** Attacker used a malicious ERC20 (token B) and a Uniswap V3 pool to inflate a balance, then called vault.mint to overwrite storage slot 1 with a large number. By deploying a contract at exactly that address via CREATE2, the attacker became the address the vault believed was the legitimate Uniswap callback caller. The attacker then invoked uniswapV3SwapCallback directly to force the vault to transfer its USDC, WBTC, and WETH to attacker-controlled addresses.
**Escalation:** Chained storage collision with CREATE2 address grinding to impersonate the trusted callback, then reused the same primitive to drain multiple assets (USDC, WBTC, WETH) in one transaction.
**Insight:** When a contract stores an address or role in a low storage slot, check whether any user-influenced write (e.g., mint amount, balance) can land in that slot; if so, CREATE2 address grinding can turn the numeric value into a real contract that passes the check.
