Core Contracts

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

Due to a serious vulnerability in the parent class BaseChainlinkFunctionsOracle, RAACPrimeRateOracle and RAACHousePriceOracle may set incorrect prices

Summary

The RAACHousePriceOracle and RAACPrimeRateOracle contracts inherit from BaseChainlinkFunctionsOracle and are designed to fetch house pricing data and prime rate from an off-chain API using Chainlink Functions. However, a critical vulnerability exists in the BaseChainlinkFunctionsOracle contract: the fulfillRequest function does not validate whether the returned requestId matches the stored s_lastRequestId. This oversight can lead to incorrect price updates in the RAACHousePriceOracle and RAACPrimeRateOracle contracts, potentially causing financial losses or data corruption.

Vulnerability Details

Both RAACHousePriceOracle and RAACPrimeRateOracle contracts inherit from BaseChainlinkFunctionsOracle

contract RAACPrimeRateOracle is BaseChainlinkFunctionsOracle {
contract RAACHousePriceOracle is BaseChainlinkFunctionsOracle {

The sendRequest function in BaseChainlinkFunctionsOracle stores the requestId of the sent request in s_lastRequestId.

function sendRequest(
string calldata source,
FunctionsRequest.Location secretsLocation,
bytes calldata encryptedSecretsReference,
string[] calldata args,
bytes[] calldata bytesArgs,
uint64 subscriptionId,
uint32 callbackGasLimit
) external onlyOwner {
...
s_lastRequestId = _sendRequest(
req.encodeCBOR(),
subscriptionId,
callbackGasLimit,
donId
);
_beforeFulfill(args);
}

The fulfillRequest function processes the response but does not verify if the returned requestId matches s_lastRequestId.

function fulfillRequest(
bytes32 requestId,
bytes memory response,
bytes memory err
) internal override {
s_lastResponse = response;
s_lastError = err;
if (err.length == 0) {
if (response.length == 0) {
revert FulfillmentFailed();
}
_processResponse(response);
}
}

If multiple requests are sent, and their responses are returned out of order, fulfillRequest might process a response intended for a different request, leading to incorrect data updates in RAACHousePriceOracle and RAACPrimeRateOracle

What's more, a malicious actor could exploit this vulnerability by crafting a fake response and calling fulfillRequest with an arbitrary requestId. This could result in unauthorized updates to house prices and prime rate, potentially manipulating the on-chain data.

Impact

  • Incorrect Price Updates: The housePrices.setHousePrice(lastHouseId, price) function in RAACHousePriceOracle could set incorrect prices due to mismatched or malicious responses. The lendingPool.setPrimeRate(lastPrimeRate) function in RAACPrimeRateOracle could set incorrect prime rate due to mismatched or malicious responses.

  • Financial Losses: If the oracle is used in a financial application, incorrect price updates could lead to financial losses for users or the protocol.

  • Data Integrity: The integrity of the house price data stored in the RAACHousePrices contract could be compromised.

The impact is High, the likelihood is Low, so the severity is Medium.

Tools Used

Manual Review

Recommendations

To mitigate this vulnerability, the fulfillRequest function should validate the requestId before processing the response. Here is the updated code:

function fulfillRequest(
bytes32 requestId,
bytes memory response,
bytes memory err
) internal override {
// Add validation to ensure the requestId matches the last request
require(requestId == s_lastRequestId, "Invalid request ID");
s_lastResponse = response;
s_lastError = err;
if (err.length == 0) {
if (response.length == 0) {
revert FulfillmentFailed();
}
_processResponse(response);
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Out of scope

Support

FAQs

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