# Repeated Calls to Shelter.withdraw Can Drain All Funds in Shelter

Shelter.withdraw lacked a per-user claim check, letting any depositor repeatedly withdraw to drain all other users' emergency funds.

- Payout: Audit contest
- Severity: high
- Program: Concur Finance
- Found by: mtz
- Disclosed: 2022-05-24
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-02-concur-findings/issues/246
- Library page: https://bugbountylibrary.com/r/c4%3A2022-02-concur%3AH-03
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:access-control vuln:business-logic

**Target:** Shelter.sol emergency withdrawal contract
**Root cause:** withdraw records claims keyed by recipient address instead of msg.sender and never checks whether the caller already withdrew, so the same caller can withdraw repeatedly.
**Steps:**
1. Mallory deposits 1 wETH into ConvexStakingWrapper; others deposit 2 wETH.
2. Owner calls setShelter(shelter) and enterShelter([pidOfWETHToken]) moving 3 wETH into Shelter.
3. Mallory calls `shelter.withdraw(wETHAddr, MalloryAddr)` and receives 1 wETH (her 1/3 share).
4. Mallory calls `shelter.withdraw(wETHAddr, MalloryAddr)` again, receiving another 1/3 share of remaining funds; repeat until drained.
**How found:** Code review of Shelter.withdraw noticed the claim mapping was keyed on the recipient address rather than msg.sender and no prior-withdrawal check existed, implying repeat calls succeed.
**Exploitation:** Attacker with any legitimate deposit waits for shelter activation, withdraws their share once, then loops withdraw calls to siphon other users' tokens since no per-sender claim state is enforced.
**Insight:** In emergency-exit contracts, verify claim/deposit accounting is keyed to msg.sender and marked before transfer; recipient-keyed or missing claim flags enable repeat-drain of pooled funds.
