# Staking tokens can be stolen

Anchor staking contract rounds share calculation down when withdrawing, letting an attacker repeatedly stake minimal amount and withdraw more than deposited for small profit.

- Payout: Audit contest
- Severity: medium
- Program: Anchor
- Found by: cmichel
- Disclosed: 2023-01-18
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-02-anchor-findings/issues/37
- Library page: https://bugbountylibrary.com/r/c4%3A2022-02-anchor%3AM-12
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium technique:source-review vuln:accounting-error vuln:business-logic

**Target:** staking contract (Rust, CosmWasm)
**Root cause:** When withdrawing, the amount is converted to shares via `amount * total_share / total_balance` rounded down, and the max(.,1) only prevents zero shares. This allows withdrawing more tokens than the shares are worth.
**Steps:**
1. Assume total_balance=2e18, total_share=1e18.
2. Attacker stakes minimal amount to receive 1 share (cost 2 tokens).
3. Attacker calls `withdraw_voting_tokens(amount=3)`.
4. withdraw_share = max(3 * 1e18 / 2e18, 1) = max(1,1) = 1 share burned.
5. Attacker receives 3 tokens, profit 1 token.
6. Repeat many times in a single transaction with many messages.
**How found:** Code review of staking contract's share calculation; noticed rounding down and that max(.,1) only handles zero-share case, not general rounding exploit.
**Exploitation:** Attacker repeatedly stakes the minimum amount to get 1 share, then withdraws specifying the largest amount that still rounds down to 1 share, extracting more tokens than deposited each cycle. Profit is small per iteration but can be repeated many times in one transaction.
**Insight:** In share-based staking/vault contracts, always round shares up when withdrawing (or recompute amount from shares) to prevent rounding-based theft; max(.,1) is insufficient.
