# KangarooVault QueuedWithdraw Denial of Service

KangarooVault queues withdrawals; a zero-amount withdrawal to the sUSD proxy address makes processWithdrawalQueue revert forever, burning later users' vault tokens.

- Payout: Contest reward
- Severity: high
- Program: Polynomial Protocol
- Credited: Lirios
- Disclosed: 2023-08-01
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-03-polynomial-findings/issues/105
- Library page: https://bugbountylibrary.com/r/c4%3A2023-03-polynomial%3AH-11
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:business-logic vuln:dos

**Target:** KangarooVault withdrawal queue / sUSD token transfer
**Root cause:** processWithdrawalQueue processes entries sequentially and reverts on any failed transfer; sUSD's _internalTransfer rejects transfers to its own proxy/implementation, so a queued entry with receiver=sUSD proxy permanently blocks the queue head.
**Steps:**
1. Open a position so withdrawals are queued (positionId != 0).
2. Attacker calls `initiateWithdrawal(0xDfA2d3a0d32F870D87f8A0d7AA6b9CdEB7bc5AdB, 0)` (sUSD MultiCollateralSynth address) to enqueue a reverting entry.
3. Victim calls `initiateWithdrawal(user, amount)`; vault tokens burned, request queued behind attacker's.
4. After minWithdrawDelay, `processWithdrawalQueue(3)` reverts with TRANSFER_FAILED at the attacker entry; queuedWithdrawalHead never advances.
5. Victim's vault tokens are burned with no SUSD received; queue permanently stuck.
**How found:** Read the withdrawal queue processing loop and noticed a single reverting entry halts the head pointer; then inspected the real sUSD token implementation and found transfers to the proxy/implementation address revert, giving a cheap way to craft a guaranteed-reverting queue entry.
**Exploitation:** Attacker frontruns a large initiateWithdrawal (or acts anytime) with a zero-amount withdrawal whose receiver is the sUSD proxy/implementation address. sUSD's _internalTransfer requires to != address(this) && to != address(proxy), so processing that entry reverts, freezing queuedWithdrawalHead and blocking all subsequent withdrawals.
**Escalation:** Can be repeated/timed to frontrun specific large withdrawals; griefs all later queued users, permanently locking their burned vault tokens.
**Insight:** When auditing queue/loop processors, check whether one failing element can halt the head pointer; then look for token-level transfer restrictions (self/proxy/blacklist/zero-address) that let an attacker cheaply enqueue a guaranteed-reverting entry, especially with zero-amount requests.
