# Draw organizer can rig the draw to favor certain participants such as their own account.

Draw host leaves Chainlink VRF subscription underfunded, then frontruns fulfillRandomWords with redraw() to discard unfavorable randomness and rig raffle winners.

- Payout: Contest reward
- Severity: high
- Program: Forgeries
- Credited: Trust
- Disclosed: 2023-02-28
- Write-up quality: 8/10
- Original: https://github.com/code-423n4/2022-12-forgeries-findings/issues/272
- Library page: https://bugbountylibrary.com/r/c4%3A2022-12-forgeries%3AH-02
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:race-window technique:source-review vuln:business-logic vuln:oracle-manipulation vuln:race-condition

**Target:** RandomDraw raffle contract using Chainlink VRFCoordinatorV2 subscription
**Root cause:** Chainlink VRF responses can arrive up to 24h after request when subscription is underfunded, while redraw cooldown can be as low as 1h; redraw() swaps currentChainlinkRequestId so the pending fulfill reverts on requestId mismatch.
**Steps:**
1. Host sets subscriptionID balance to 0 LINK in VRFCoordinatorV2
2. Host calls `startDraw()` which calls `coordinator.requestRandomWords(...)` and stores request.currentChainlinkRequestId
3. Wait past redraw cooldown (e.g. 2h), then top up subscriptionID with LINK so Chainlink node submits fulfillRandomWords TX
4. Scan mempool for the fulfillRandomWords transaction
5. If random outcome favors host, let fulfill execute; otherwise call `redraw()` to swap currentChainlinkRequestId before fulfill lands
6. fulfillRandomWords reverts with REQUEST_DOES_NOT_MATCH_CURRENT_ID; repeat until favorable outcome
**How found:** Researcher read Chainlink VRF subscription docs noting pending requests can wait up to 24h when underfunded, then compared that window against the contract's redraw cooldown and the requestId equality check in fulfillRandomWords, realizing redraw() invalidates pending responses.
**Exploitation:** Host controls subscription funding and redraw timing; by keeping subscription empty they delay the VRF response, then fund it and frontrun the fulfill TX with redraw() to invalidate unfavorable randomness, biasing winner selection toward their own tokenIDs.
**Escalation:** Repeatable across every raffle, compounding the host's edge over time; also halves any unwanted recipient's win chance.
**Insight:** When a contract consumes an async oracle (VRF, price feed, callback) with a requestId guard, check whether any user-triggerable action can rotate the stored requestId before the callback lands; also compare oracle latency bounds (e.g. 24h pending window) against any cooldown that is supposed to guarantee the response arrived.
