Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: medium
Valid

`fulfillRequest` does not validate `requestId`

Summary

The fulfillRequest function does not validate the requestId against the s_lastRequestId set in sendRequest.

Vulnerability Details

The RAAC protocol retrieves the price of RAACHouse NFTs using a Chainlink function. The process follows these steps:

  1. The Chainlink cron job calls RAACHousePriceOracle::sendRequest.

  2. The sendRequest function sets s_lastRequestId.

  3. The function then calls _beforeFulfill, as shown in the code below.

  4. Chainlink than calls fulfillRequest to set the house price.

/contracts/core/oracles/BaseChainlinkFunctionsOracle.sol:71
71: s_lastRequestId = _sendRequest(
72: req.encodeCBOR(),
73: subscriptionId,
74: callbackGasLimit,
75: donId
76: );
77: _beforeFulfill(args);

the _beforeFulfill sets the lastHouseId

/contracts/core/oracles/RAACHousePriceOracle.sol:34
34: function _beforeFulfill(string[] calldata args) internal override {
35: lastHouseId = args[0].stringToUint();
36: }

The fulfillRequest receives the requestId and calls _processResponse.

/contracts/core/oracles/RAACHousePriceOracle.sol:42
42: function _processResponse(bytes memory response) internal override {
43: uint256 price = abi.decode(response, (uint256));
44: housePrices.setHousePrice(lastHouseId, price);
45: emit HousePriceUpdated(lastHouseId, price);
46: }

The _processResponse sets the price against lastHouseId by calling RAACHousePrices::setHousePrice. and the protocol can call RAACHousePrices::getLatestPrice to get the latest price of RAAC House.

However fulfillRequest never confirms that the requestId it receives matches s_lastRequestId.

Stepwise Explanation of the Issue

  1. The cron job submits _sendRequest for NFTId 1 and sets s_lastRequestId = 0x1234.

  2. This also sets lastHouseId = 1 in the _beforeFulfill function.

  3. While the contract is waiting for fulfillRequest,

  4. The cron job submits another _sendRequest for NFTId 2 and sets s_lastRequestId = 0x8976.

  5. Now lastHouseId = 2. The Chainlink function calls fulfillRequest for NFTId = 1 with requestID = 0x1234.

  6. In the _processResponse function, the price of lastHouseId = 2 is incorrectly set with the price of lastHouseId = 1.

This sequence of events leads to incorrect pricing for NFTs, resulting in a mismatch between requestId and lastHouseId.
Note : BaseChainlinkFunctionsOracle is not in direct scope , but the contract which will be effected by this issue are in scope.

Impact

A mismatch in requestId will result in an incorrect price being set for the lastHouseId. While the likelihood of this happening may be low, the impact is significant, as the wrong price will be associated with an NFT.
This issue qualifies as a medium severity vulnerability.

Tools Used

Manual Review

Recommendations

Include a check to ensure fulfillRequest uses the correct requestId as mentioned in the chainlink docs.
For example:

diff --git a/contracts/core/oracles/BaseChainlinkFunctionsOracle.sol b/contracts/core/oracles/BaseChainlinkFunctionsOracle.sol
index 1c7b15a..aafcf1d 100644
--- a/contracts/core/oracles/BaseChainlinkFunctionsOracle.sol
+++ b/contracts/core/oracles/BaseChainlinkFunctionsOracle.sol
@@ -101,7 +101,9 @@ abstract contract BaseChainlinkFunctionsOracle is FunctionsClient, ConfirmedOwne
bytes memory response,
bytes memory err
) internal override {
-
+ if (s_lastRequestId != requestId) {
+ revert FulfillmentFailed(); // Check if request IDs match
+}
s_lastResponse = response;
s_lastError = err;
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Oracle Race Condition in RAACHousePriceOracle causes price misassignment between NFTs

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Oracle Race Condition in RAACHousePriceOracle causes price misassignment between NFTs

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!