Reproduced Exploit
BOB Staking — Delegating to address(0) empties contract via alterGovernanceDelegatee
1. First non-zero delegation moves the staker's tokens contract → surrogate. 2. Setting delegatee to address(0) is allowed; tokens move to a zero surrogate. 3. Re-delegating to a non-zero address sees governanceDelegatee == 0 and treats it as a first delegation. 4. The contract transfers amountStak…
Chain
Other
Category
logic
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: 63720-h-02-delegating-to-address0-empties-contract-via-altergovern. Standalone Foundry PoC and full write-up: 63720-h-02-delegating-to-address0-empties-contract-via-altergovern_exp in the
evm-hack-registrymirror.
Vulnerability classes: vuln/logic/missing-check · direct-drain · vote-delegation-loop
Reproduction: a self-contained Foundry PoC that compiles & runs in an isolated project with only
forge-std— no fork, no RPC, noanvil_state. Full trace: output.txt. PoC: test/63720-h-02-delegating-to-address0-empties-contract-via-altergovern_exp.sol.
AuditVault taxonomy: severity/high · sector/staking · sector/governance · platform/pashov · missing · direct-drain · reward-accounting · vote-delegation-loop
Key info#
| Impact | HIGH — attacker drains staking-contract balance (rewards / other stakes) |
| Protocol | BOB Staking |
| Vulnerable code | BobStaking.alterGovernanceDelegatee — allows address(0) and re-pulls from contract |
| Bug class | Missing zero-address reject + wrong "first delegation" branch after undelegate |
| Finding | Pashov BOB-Staking security review 2025-10-18 · #63720 |
| Report | Pashov BOB-Staking review |
| Source | AuditVault |
| Status | Audit finding — resolved per report (disable address(0)). Reproduced as a reduced local synthetic. |
| Compiler | ^0.8.24 (PoC) |
TL;DR#
- First non-zero delegation moves the staker's tokens contract → surrogate.
- Setting delegatee to
address(0)is allowed; tokens move to a zero surrogate. - Re-delegating to a non-zero address sees
governanceDelegatee == 0and treats it as a first delegation. - The contract transfers
amountStakedfrom its own balance (rewards) into the new surrogate — draining the vault. Repeat to empty it.
The vulnerable code#
function alterGovernanceDelegatee(address newDelegatee) external {
// FIX: revert if newDelegatee == address(0)
DelegationSurrogate newSurrogate = _fetchOrDeploySurrogate(newDelegatee);
if (staker.governanceDelegatee == address(0)) { // @> VULN after prior 0-delegate
IERC20(stakingToken).safeTransfer(address(newSurrogate), staker.amountStaked);
} else {
// move between surrogates
}
staker.governanceDelegatee = newDelegatee;
}
Root cause#
address(0) is both the "not yet delegated" sentinel and an allowed target. After a real undelegate-to-zero, the user's tokens sit in the zero surrogate, but the next re-delegate reuses the first-time path that pulls from the main contract.
Preconditions#
- Attacker has non-zero stake.
- At least one whitelisted non-zero delegatee.
- Contract holds extra tokens (rewards or other stakers) ≥
amountStakedper cycle.
Attack walkthrough#
- Deposit 1000e18 rewards; attacker stakes 1e18.
- Delegate to a whitelisted address (stake leaves contract).
- Delegate to
address(0)(tokens → zero surrogate). - Delegate again to the non-zero address → pulls 1e18 from rewards into the surrogate.
- Contract rewards fall from 1000 → 999; repeat to empty.
Diagrams#
Impact#
Any staker can siphon reward inventory (and eventually other users' undelegated stake) by cycling D → 0 → D. Full vault empty is possible with enough cycles.
Sources#
Sources & further analysis#
Reproductions & code
- Standalone PoC + full trace: 63720-h-02-delegating-to-address0-empties-contract-via-altergovern_exp (evm-hack-registry mirror).
- AuditVault finding: 63720-h-02-delegating-to-address0-empties-contract-via-altergovern.
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.