# An attacker can leave the protocol in a "drawing" state for extended period of time

Attacker calls executeDraw/retry with insufficient gas so Chainlink VRF request reverts inside try/catch, leaving lottery stuck in drawing state for maxRequestDelay.

- Payout: Contest reward
- Severity: medium
- Program: Wenwin
- Credited: alexxander
- Disclosed: 2023-04-12
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-03-wenwin-findings/issues/521
- Library page: https://bugbountylibrary.com/r/c4%3A2023-03-wenwin%3AM-02
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:race-window technique:source-review vuln:business-logic vuln:dos

**Target:** RNSourceController.sol / VRFv2RNSource.sol lottery RNG controller
**Root cause:** requestRandomNumberFromSource sets lastRequestFulfilled=false before calling source.requestRandomNumber() inside try/catch; an out-of-gas revert is swallowed by catch (caller retains 1/64 gas), leaving state stuck until maxRequestDelay.
**Steps:**
1. Wait until ticket registration closes for current draw.
2. Call `executeDraw()` with insufficient gas so the inner VRF request reverts out-of-gas but catch clause still executes.
3. Front-run any competing `executeDraw()` transactions to keep the malicious one first.
4. State remains `drawExecutionInProgress=true` and `lastRequestFulfilled=false`; wait maxRequestDelay (~5h).
5. Call `retry()` with insufficient gas, front-running competing retries, repeating to extend the drawing state indefinitely.
**How found:** Code review of RNSourceController request flow; noticed try/catch swallows VRF revert after state flag set, then reasoned about out-of-gas and 1/64 gas retention to confirm catch still completes.
**Exploitation:** Attacker repeatedly submits gas-starved executeDraw/retry transactions, front-running honest ones, so the VRF request always reverts inside try/catch and the protocol stays in drawing state; no LINK deposit needed since VRF also reverts on insufficient LINK.
**Escalation:** Repeated retry() calls each add maxRequestDelay (~5h) of stalled drawing; text notes swapSource() after maxFailedAttempts could break fairness and enable jackpot theft.
**Insight:** When a state flag is set before a try/catch external call, check whether an out-of-gas revert can be swallowed: Solidity retains 1/64 gas so the catch clause may still run, permanently desyncing state until a cooldown.
