Reproduced Exploit
Statusl — bypass stake lock via leave + migrateToVault
1. Stake with a multi-year lock for max multiplier. 2. leave() zeros stakedBalance but does not permanently ban the vault as a migrate target. 3. An empty vault migrates onto the left vault and overwrites lockUntil with 0. 4. Withdraw the full stake immediately.
Chain
Other
Category
untagged
Date
Jan 2026
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: 65328-user-can-bypass-lock-and-withdraw-stake-anytime-cyfrin-none. Standalone Foundry PoC and full write-up: 65328-user-can-bypass-lock-and-withdraw-stake-anytime-cyfrin-none_exp in the
evm-hack-registrymirror.
Vulnerability classes: wrong-condition · indirect-loss · reward-accounting
Reproduction: self-contained Foundry PoC with only
forge-std. Full trace: output.txt. PoC: test/65328-user-can-bypass-lock-and-withdraw-stake-anytime-cyfrin-none_exp.sol.
AuditVault taxonomy: lang/solidity · platform/cyfrin · has/github · has/poc · severity/high · sector/staking · genome: wrong-condition · indirect-loss · reward-accounting
Key info#
| Impact | HIGH — max-lock stake withdrawable immediately; up to 3x unfair reward share |
| Protocol | Status Network / Statusl |
| Vulnerable code | StakeManager.leave + migrateToVault / StakeVault.migrateFromVault |
| Bug class | Missing hasLeft guard on migration target |
| Finding | Cyfrin Statusl2 v2.0, 2026-01-05 · #65328 · Samuraii77 |
| Report | Cyfrin report |
| Source | AuditVault |
| Status | Fixed in fb6c8ef |
| Compiler | ^0.8.24 (PoC) |
TL;DR#
- Stake with a multi-year lock for max multiplier.
leave()zerosstakedBalancebut does not permanently ban the vault as a migrate target.- An empty vault migrates onto the left vault and overwrites
lockUntilwith 0. - Withdraw the full stake immediately.
- HARM: lock bypass — max rewards with no lock downside.
The vulnerable code#
_unstake(vault.stakedBalance, vault); // @> VULN: leave without blocking migrate-to
// ...
if (vaultOwners[migrateTo] == address(0)) revert; // @> VULN: no hasLeft check
if (vaultData[migrateTo].stakedBalance > 0) revert;
// ...
lockUntil = data.lockUntil; // @> VULN: empty source clears lock
Fix: disallow migrating to (or from) a vault with hasLeft == true.
Root cause#
Migration only checks registration and zero staked balance. A vault that has left is empty and still registered, so it accepts a migrate that writes lockUntil = 0.
Preconditions#
- User can create multiple vaults and call leave/migrate.
- Stake locked for a long period.
Attack walkthrough#
- Stake 1000 tokens with a 4-year lock on vault A.
- Create empty vault B.
leaveon A — stake accounting cleared, tokens return to vault,hasLeftset but unused by migrate.- B migrates to A with zero lock metadata → A.
lockUntil = 0. - Withdraw full stake from A immediately.
Diagrams#
Impact#
Users take max lock multiplier (6x vs 2x unlocked) then exit instantly, diluting honest locked stakers' rewards.
Sources#
Sources & further analysis#
Reproductions & code
- Standalone PoC + full trace: 65328-user-can-bypass-lock-and-withdraw-stake-anytime-cyfrin-none_exp (evm-hack-registry mirror).
- AuditVault finding: 65328-user-can-bypass-lock-and-withdraw-stake-anytime-cyfrin-none.
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.