Reproduced Exploit

Blend v2 — Steal other users' emissions via vulnerable claim

1. execute_claim can deposit exchanged backstop LP to a different to address. 2. It updates to's share balance without update_emissions(to). 3. A fresh to later claims with default index 0 while holding shares → accrues full historical index. 4. Stolen inventory leaves other users unable to claim.

Feb 2025Otheruntagged2 min read

Chain

Other

Category

untagged

Date

Feb 2025

Source

AuditVault

EVM Playground

Source-level debugger — step opcodes and Solidity in sync

evm-hack-analyzer

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.

Loading fork state…

Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: 62062-h-02-user-can-steal-other-users-emissions-due-to-vulnerable. Standalone Foundry PoC and full write-up: 62062-h-02-user-can-steal-other-users-emissions-due-to-vulnerable_exp in the evm-hack-registry mirror.


Vulnerability classes: reward-theft · lockup · missing emission checkpoint

Reproduction: self-contained Foundry PoC (Solidity reduction of Soroban backstop emissions accounting) with only forge-std — no fork. Full trace: output.txt.


Key info#

ImpactHIGH — claim-to-third-party deposits shares without emission init → inflated claim steals inventory
ProtocolBlend v2 — backstop emissions
Vulnerable codeexecute_claim adds shares to to without update_emissions(to)
FindingCode4rena — 2025-02-blend · #62062 · [H-02] · reporter oakcobalt
Reportcode4rena.com/reports/2025-02-blend-v2-audit-certora-formal-verification
SourceAuditVault
Compiler^0.8.24 (PoC synthetic; original is Soroban/Rust)

TL;DR#

  1. execute_claim can deposit exchanged backstop LP to a different to address.
  2. It updates to's share balance without update_emissions(to).
  3. A fresh to later claims with default index 0 while holding shares → accrues full historical index.
  4. Stolen inventory leaves other users unable to claim.

The vulnerable code#

SOLIDITY
// Deposit LP tokens into pool backstop
let to_mint = pool_balance.convert_to_shares(deposit_amount);
pool_balance.deposit(deposit_amount, to_mint);
// @audit missing update_emissions(to)
user_balance.add_shares(to_mint); // @> VULN

Root cause#

Share balance and emission index must be checkpointed atomically. Skipping the checkpoint on the deposit recipient leaves them able to claim unearned historical emissions.

Diagrams#

sequenceDiagram participant A as userA participant C as addressC participant B as Backstop participant V as userB A->>B: execute_claim(to=addressC) Note over B: shares to C without update_emissions(C) C->>B: claim_to_wallet (index default 0) Note over B: inflated accrual drains inventory V->>B: claim - reverts insufficient inventory

Impact#

Direct theft of other depositors' emissions budget; victim claims fail for lack of inventory.

Sources#

Taxonomy: [[direct-drain]] · [[lockup]] · severity/high · sector/lending


Sources & further analysis#

Reproductions & code

Alerts & third-party analyses

  • Web3Sec X hacked database: search.
  • Rekt leaderboard: search.
  • Solodit incident search: search.

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.