DeFiHardhatFoundry
250,000 USDC
View results
Submission Details
Severity: low
Invalid

Spam vulnerability and non-indexed events hinder the usability of the `publishRequisition` function

Summary

The publishRequisition function in the TractorFacet contract of the Beanstalk project is vulnerable to spam attacks and produces non-indexed events, making it difficult to read and utilize the emitted data effectively.

Vulnerability Details

TractorFacet.sol#L66-L70

function publishRequisition(
LibTractor.Requisition calldata requisition
) external verifyRequisition(requisition) {
emit PublishRequisition(requisition);
}
  1. Spam Vulnerability: The function allows users to publish an unlimited number of Requisitions, leading to potential spam attacks. Malicious actors could use this to exploit the system by publishing numerous fake Requisitions. This can flood the system with irrelevant data and incur unnecessary gas costs for operators who try to execute some of the fake Requisitions. The worst-case scenario would be attackers flooding the system, causing multiple tractor operators to pay unnecessary gas costs and resulting in fund losses for them. This can significantly impact the reputation of TractorFacet, deterring users from executing anything published on the blockchain due to the risk of it being fake.

  2. Non-indexed Events: The emitted PublishRequisition events lack indexed fields, making it difficult to filter and search the events efficiently. This hinders usability and effective tracking of Requisitions.

PublishRequisition event

event PublishRequisition(LibTractor.Requisition requisition);

LibTractor.Requisition struct which is emitted in the event

struct Requisition {
Blueprint blueprint;
bytes32 blueprintHash; // including this is not strictly necessary, but helps avoid hashing more than once on chain
bytes signature;
}

Blueprint struct

struct Blueprint {
address publisher;
bytes data;
bytes32[] operatorPasteInstrs;
uint256 maxNonce;
uint256 startTime;
uint256 endTime;
}

PoC

My PoC consists of a contract deployed to the Sepolia testnet to show how the event looks without indexed fields and how hard it is to utilize.

Contract which emits event without indexed fields
contract Publisher {
struct Blueprint {
address publisher;
bytes data;
uint256 maxNonce;
uint256 startTime;
uint256 endTime;
}
struct Requisition {
Blueprint blueprint;
bytes32 blueprintHash; // including this is not strictly necessary, but helps avoid hashing more than once on chain
bytes signature;
}
event PublishRequisition(Requisition requisition);
function buildRequisition() external {
Blueprint memory blueprint = Blueprint(
msg.sender,
"0x",
15,
block.timestamp,
block.timestamp + 10
);
Requisition memory requisition = Requisition(
blueprint,
keccak256(abi.encode(blueprint)),
"0x"
);
emit PublishRequisition(requisition);
}
}

I invoked the function once to emit the event. Here is how it looks on the blockchain: https://sepolia.etherscan.io/address/0xd55a210d98a42fe472bce683128a5cb01c19af4c#events


I also wrote a contract with an indexed event, adding indexed fields to important parameters.

Contract with indexed fields
pragma solidity ^0.8.20;
contract Publisher {
struct Blueprint {
address publisher;
bytes data;
uint256 maxNonce;
uint256 startTime;
uint256 endTime;
}
struct Requisition {
Blueprint blueprint;
bytes32 blueprintHash; // including this is not strictly necessary, but helps avoid hashing more than once on chain
bytes signature;
}
event PublishRequisition(
address indexed publisher,
bytes32 indexed blueprintHash,
uint256 maxNonce,
uint256 startTime,
uint256 endTime
);
function buildRequisition() external {
Blueprint memory blueprint = Blueprint(
msg.sender,
"0x",
15,
block.timestamp,
block.timestamp + 10
);
Requisition memory requisition = Requisition(
blueprint,
keccak256(abi.encode(blueprint)),
"0x"
);
emit PublishRequisition(
blueprint.publisher,
requisition.blueprintHash,
blueprint.maxNonce,
blueprint.startTime,
blueprint.endTime
);
}
}

Here is the event it produced: https://sepolia.etherscan.io/address/0xe7bc7c9378b89a578a91313f448e6638530a1a2f#events

Impact

  • System flooding: Attackers can exploit the function to flood the system with numerous fake Requisitions, making it challenging to identify and process genuine ones.

  • Tractor operators paying unnecessary gas costs while trying to execture spam Requisitions

  • Reduced usability: The lack of indexed fields in the events makes it hard for users to query and utilize the event data effectively.

Tools Used

Remix, Sepolia Testnet

Recommendations

Completely remove the publishRequisition function and manage the Requisitions off-chain by creating an appropriate marketplace for transactions, for example in the Beanstalk web app. This approach can effectively prevent spam and reduce on-chain data clutter. Additionally, this off-chain management system would provide greater readability regarding the source of the request, visualize whether there is a reward for executing a blueprint, and overall, offer a superior user experience.

Updates

Lead Judging Commences

inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational/Gas

Invalid as per docs https://docs.codehawks.com/hawks-auditors/how-to-determine-a-finding-validity

Support

FAQs

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