Weather Witness

First Flight #40
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: high
Valid

Oracle Error Silently Breaks Mint Flow, Causing Permanent Fund Lock

Summary

The WeatherNft::fulfillMintRequest function finalizes the minting process of a Weather NFT, relying on the result of an off-chain oracle (Chainlink Functions) call. However, the contract does not revert or provide a retry mechanism when the oracle response contains an error. Instead, if the oracle call fails (i.e., err.length > 0), the function simply returns silently, leaving the user’s mint request unresolved.

As a result, users who have paid the minting fee may find their requests permanently stuck, unable to receive their NFT or recover their funds. This could lead to loss of user funds, degraded user experience, and potentially open the door to Denial of Service (DoS) attacks by intentionally triggering oracle errors.


Vulnerability Details

function fulfillMintRequest(bytes32 requestId) external {
bytes memory response = s_funcReqIdToMintFunctionReqResponse[requestId].response;
bytes memory err = s_funcReqIdToMintFunctionReqResponse[requestId].err;
require(response.length > 0 || err.length > 0, WeatherNft__Unauthorized());
if (response.length == 0 || err.length > 0) {
// @audit-issue Silent return, user can never complete mint if oracle fails
@> return;
}
// ...mint logic...
}

Issue Identified

  • The contract does not handle oracle errors robustly during the minting process.

  • If the Chainlink Functions oracle call returns an error, the function simply returns, and does not revert, refund, or allow the user to retry.

  • The user’s paid mint request becomes permanently stuck:

    • No NFT is minted

    • No ETH refund

    • No event signaling the failure

  • There is no mechanism for the user or admin to recover or reprocess the stuck request.


Risk

Likelihood:

  • This can be triggered any time the Chainlink oracle fails due to network issues, misconfiguration, or by submitting invalid data (pincode/ISO).

  • Malicious users could attempt to spam the system with invalid oracle requests, increasing the risk of stuck mints.

Impact:

  • Permanent loss of user funds for affected mint requests.

  • Degraded user trust and experience.

  • Potential accumulation of stuck requests in contract storage, leading to increased gas costs and storage bloat.


Tools Used

  • Manual Review

  • Custom Unit Testing (simulate oracle errors during mint)


Recommendations

Implement Automatic Refund in fulfillMintRequest

If the oracle call fails (err.length > 0 or response.length == 0), automatically refund the minting fee to the user and emit a refund event.
This ensures users won’t lose funds due to oracle errors.

if (response.length == 0 || err.length > 0) {
+ address user = s_funcReqIdToUserMintReq[requestId].user;
+ uint256 refund = /* original mint price */;
+ (bool sent, ) = user.call{value: refund}("");
+ require(sent, "Refund failed");
+ emit MintRefunded(user, requestId, refund, string(err));
return;
}

This ensures users are not left with unresolved or lost mint requests and that the contract handles oracle errors transparently, improving protocol reliability and user trust.


Updates

Appeal created

bube Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Lost fee in case of Oracle failure

If Oracle fails, the `fulfillMintRequest` function will not return the payed fee for the token to the user.

Support

FAQs

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