F-2025-0011·vrf-revert

fulfillRandomWords may revert, causing loss of funds and DoS in rewards distribution

Fixedrafflelotteryvrf
TL;DR

fulfillRandomWords performs reward distribution that can revert on a single blacklisted recipient or insufficient balance, permanently locking the round per Chainlink VRF semantics.

Severity
MEDIUM
Impact
MEDIUM
Likelihood
MEDIUM
Method
MManual review
CAT.
Complexity
MEDIUM
Exploitability
MEDIUM
02Section · Description

Description

The function fulfillRandomWords is only callable by chainlink VRF to select a raffle winner when all tickets of a product have been bought. Because it can't be called manually, and because it handles distribution of funds, the function execution must never revert, or the contract will remain in a state where the product's round can't change, and funds will never be distributed.

Here are the possible reasons why the function may revert:

  • The contract has less funds than the total to distribute (unlikely, as funds are drawn when users are paying for tickets)
  • Any address to which the tokens are supposed to be sent is blacklisted (low likelyhood, this rarely happens)

This link refers to Chainlink's official documentation regarding reverts using VRF: https://docs.chain.link/vrf/v2-5/security#fulfillrandomwords-must-not-revert

Vulnerable Scenario:

The following steps help understand the issue:

  1. Users buy all tickets for the raffle
  2. The contract calls Chainlink VRF to select a winner
  3. One of the user who should receive stablecoins from the raffle is blacklisted
  4. When NexumManager receives the VRF response, it immediately executes the rewards calculations and transfers
  5. Because a receiver is blacklisted, fulfillRandomWords reverts
  6. fulfillRandomWords cannot be called with the same requestId again
  7. The raffle product's round cannot increase, so we can't keep on using it for the raffles, and users can't receive rewards
03Section · Impact

Impact

  • In the worst case scenario where the randomness can not be fulfilled, the raffle for this product will stop working and the rewards will remain stuck in the contract NexumManager.
  • It is important that fulfillRandomWords and every functions it calls must never revert, as the contract will enter a state that cannot be fixed then: the distribution will not occur, resulting in loss of funds, and the raffle for this product will permanently be deactivated (DoS).
04Section · Recommendation

Recommendation

  • Ensure the function can not revert under any condition (remove all require in fulfillRandomWords and called functions, and ensure external calls cannot revert).

  • Consider implementing a pull-base functionnality for reward distributions, so users will pull the funds themselves. For example:

solidity
function _newRewards(address user, uint256 amount) private {
pendingRewards[user] += amount;
}
function claimRewards(address user, uint256 amount) external {
pendingRewards[user] -= amount;
_safeTransfer(user, amount);
}
05Section · Resolution

Resolution

Nexalo: Fixed.

Zealynx: Verified. Fixed.

Status
Fixed
F-2025-0011

oog
zealynx

Smart Contract Security Digest

Monthly exploit breakdowns, audit checklists, and DeFi security research — straight to your inbox

© 2026 Zealynx