Dria

Swan
NFTHardhat
21,000 USDC
View results
Submission Details
Severity: medium
Invalid

Potential Denial of Service (DoS) Risk in purchase Function of BuyerAgent.sol

Summary

The purchase function in the BuyerAgent.sol contract has been identified to potentially expose the protocol to Denial of Service (DoS) attacks due to an unbounded for loop iterating over an array of asset addresses returned by an oracle.

Vulnerability Details

The purchase function iterates over an array of assets obtained from the oracle using the oracleResult(taskId) function.
The loop processes each asset and executes external calls to retrieve the listing price and purchase the asset.
If the array of assets is large, the cumulative gas cost of executing the loop may exceed the block gas limit, leading to transaction failures. This could potentially allow an attacker to exploit the system by providing an excessive number of assets in the oracle response, causing legitimate transactions to fail and preventing users from interacting with the contract.

The issue can be found here: https://github.com/Cyfrin/2024-10-swan-dria/blob/main/contracts/swan/BuyerAgent.sol#L222-L256

function purchase() external onlyAuthorized {
// check that we are in the Buy phase, and return round
(uint256 round,) = _checkRoundPhase(Phase.Buy);
// check if the task is already processed
uint256 taskId = oraclePurchaseRequests[round];
if (isOracleRequestProcessed[taskId]) {
revert TaskAlreadyProcessed();
}
// read oracle result using the latest task id for this round
bytes memory output = oracleResult(taskId);
address[] memory assets = abi.decode(output, (address[]));
// we purchase each asset returned
for (uint256 i = 0; i < assets.length; i++) {
address asset = assets[i];
// must not exceed the roundly buy-limit
uint256 price = swan.getListingPrice(asset);
spendings[round] += price;
if (spendings[round] > amountPerRound) {
revert BuyLimitExceeded(spendings[round], amountPerRound);
}
// add to inventory
inventory[round].push(asset);
// make the actual purchase
swan.purchase(asset);
}
// update taskId as completed
isOracleRequestProcessed[taskId] = true;
}

Impact

Legitimate users may be unable to execute transactions due to high gas costs leading to failures.

Tools Used

Manual Review

Recommendations

Introduce a cap on the number of assets that can be processed in a single transaction. This will help ensure that the gas cost remains within acceptable limits.
Ex:

uint256 constant MAX_ASSETS = 20; // Example limit
require(assets.length <= MAX_ASSETS, "Too many assets to process in a single transaction");
Updates

Lead Judging Commences

inallhonesty Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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