Reproduced Exploit
Strata Tranches — sUSDe withdrawers always incur a loss (inverted CDO params)
1. Withdraw of 100 sUSDe (worth 150 USDe at 1.5 rate) burns 150 JRT shares. 2. Tranche passes (baseAssets, tokenAssets) but CDO expects (tokenAmount, baseAssets). 3. Strategy runs previewWithdraw(tokenAssets) instead of previewWithdraw(baseAssets) → ~66.67 sUSDe out. 4. User permanently loses USDe…
Chain
Other
Category
untagged
Date
Oct 2025
Source
AuditVault
EVM Playground
Source-level debugger — step opcodes and Solidity in sync
The attack is replayed in an in-browser EVM preloaded with the exact dumped fork state. The execution tree shows every call; step by Solidity line or by opcode across all depths — source, Stack, Memory, Storage, Balances (native / ERC-20 / NFT), Transient storage and Return value stay in sync. Click a tree node, opcode, or source line to jump. No backend, no live RPC.
Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: 63222-withdrawers-of-susde-always-incur-a-loss-because-parameters. Standalone Foundry PoC and full write-up: 63222-withdrawers-of-susde-always-incur-a-loss-because-parameters_exp in the
evm-hack-registrymirror.
Vulnerability classes: wrong-order · indirect-loss · parameter-swap
Reproduction: self-contained Foundry PoC, forge-std only, no fork. Full trace: output.txt.
AuditVault taxonomy: severity/high · sector/oracle · sector/staking · platform/cyfrin · wrong-order · indirect-loss
Key info#
| Impact | HIGH — withdrawer burns full Tranche shares but receives ~66% of requested sUSDe |
| Protocol | Strata Tranches v2.0 |
| Vulnerable code | Tranche::_withdraw → cdo.withdraw(..., baseAssets, tokenAssets) inverted |
| Bug class | Swapped call arguments |
| Finding | Cyfrin · Strata 2025-10-08 · #63222 |
| Report | Cyfrin Strata |
| Compiler | ^0.8.24 |
TL;DR#
- Withdraw of 100 sUSDe (worth 150 USDe at 1.5 rate) burns 150 JRT shares.
- Tranche passes
(baseAssets, tokenAssets)but CDO expects(tokenAmount, baseAssets). - Strategy runs
previewWithdraw(tokenAssets)instead ofpreviewWithdraw(baseAssets)→ ~66.67 sUSDe out. - User permanently loses USDe value relative to burned shares.
The vulnerable code#
cdo.withdraw(address(this), token, baseAssets, tokenAssets, receiver); // @> VULN inverted
// FIX: cdo.withdraw(address(this), token, tokenAssets, baseAssets, receiver);
Root cause#
Argument order mismatch between Tranche and CDO/Strategy withdraw APIs.
Preconditions#
- sUSDe/USDe exchange rate ≠ 1 (after yield).
- User withdraws sUSDe (not plain USDe).
Attack walkthrough#
- Bootstrap sUSDe rate to 1.5 via yield donation.
- Deposit 100 sUSDe → 150 JRT.
- Withdraw 100 sUSDe → all shares burned, ~66.67 sUSDe returned.
Diagrams#
Impact#
Every sUSDe withdrawal under-pays the user while burning full share entitlement.
Sources#
- AuditVault #63222
- Cyfrin Strata Tranches v2.0
- Fixed: Strata-Money/contracts-tranches@31d9b72
Sources & further analysis#
Reproductions & code
- Standalone PoC + full trace: 63222-withdrawers-of-susde-always-incur-a-loss-because-parameters_exp (evm-hack-registry mirror).
- AuditVault finding: 63222-withdrawers-of-susde-always-incur-a-loss-because-parameters.
Alerts & third-party analyses
These dashboards index community alerts tweets, post-mortems, and independent write-ups. Reach them through the protocol name above to cross-check this reproduction against other analyses.