code-423n4 / 2023-05-ajna-findings

2 stars 0 forks source link

Proposed Token Request Exceeds Available Funds Check Missing. #429

Closed code423n4 closed 1 year ago

code423n4 commented 1 year ago

Lines of code

https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/base/StandardFunding.sol#L366-L404 https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/base/StandardFunding.sol#L390-L391 https://github.com/code-423n4/2023-05-ajna/blob/276942bc2f97488d07b887c8edceaaab7a5c3964/ajna-grants/src/grants/base/StandardFunding.sol#L385-L391

Vulnerability details

Impact

The proposeStandard function in StandardFunding.sol contract does not include a direct check to ensure that the proposed tokens requested are less than or equal to the actual available funds for the distribution period. Instead, it only checks if the proposed tokens requested exceed 90% of the distribution period's available funds. #L390-L391

        // revert if proposal requested more tokens than are available in the distribution period
        if (newProposal.tokensRequested > (currentDistribution.fundsAvailable * 9 / 10)) revert InvalidProposal();

This line will only prevent proposals from requesting more tokens than 90% of the available funds for the distribution period, which is a good measure to ensure that proposals do not exhaust the funds allocated for the period. However, this check does not directly verify that the proposed tokens requested are less than or equal to the actual available funds for the period, which is the more critical measure to prevent the loss of funds.

If the fundsAvailable value is inaccurate or has been manipulated by an attacker, then the check newProposal.tokensRequested > (currentDistribution.fundsAvailable * 9 / 10) could still allow proposals to request more tokens than the actual available funds, leading to a loss of funds.

Proof of Concept

The proposed token request exceeding available funds check missing in the proposeStandard function can be exploited by an attacker to propose a large amount of tokens that exceed the actual available funds, potentially causing a loss of funds. StandardFunding.sol#L385-L391

        // store new proposal information
        newProposal.proposalId      = proposalId_;
        newProposal.distributionId  = currentDistribution.id;
        newProposal.tokensRequested = _validateCallDatas(targets_, values_, calldatas_); // check proposal parameters are valid and update tokensRequested

        // revert if proposal requested more tokens than are available in the distribution period
        if (newProposal.tokensRequested > (currentDistribution.fundsAvailable * 9 / 10)) revert InvalidProposal();

The function checks if the proposed tokens requested exceed 90% of the distribution period's available funds, but does not directly check if the proposed tokens requested are less than or equal to the actual available funds.

For Instance: An attacker can propose a large amount of tokens that exceed the actual available funds. Suppose the actual available funds for the distribution period are 100,000 tokens, but the fundsAvailable value is set to 200,000 tokens. An attacker can then propose to request 150,000 tokens, which will be approved by the contract as it is less than 90% of the fundsAvailable value, but exceeds the actual available funds. This will cause a loss of 50,000 tokens, as the contract will transfer the requested tokens without verifying if they are within the actual available funds.

Tools Used

Manual review, vscode

Recommended Mitigation Steps

Add an additional check to ensure that the proposed tokens requested are less than or equal to the actual available funds for the distribution period. This can be achieved by keeping track of the total amount of tokens requested by all proposals, and subtracting this value from the distribution period's available funds to obtain the actual available funds. Then, the function can check if the proposed tokens requested exceed the actual available funds, and revert if this is the case.

uint256 totalTokensRequested = 0;

// loop through existing proposals to calculate total tokens requested
for (uint256 i = 0; i < _standardFundingProposals.length; i++) {
    if (_standardFundingProposals[i].distributionId == currentDistribution.id) {
        totalTokensRequested += _standardFundingProposals[i].tokensRequested;
    }
}

// calculate actual available funds by subtracting total tokens requested from funds available
uint256 actualFundsAvailable = currentDistribution.fundsAvailable - totalTokensRequested;

// revert if proposal requested more tokens than are available in the distribution period
if (newProposal.tokensRequested > actualFundsAvailable) revert InvalidProposal();

By implementing this check, the contract can ensure that the proposed tokens requested do not exceed the actual available funds for the distribution period, and prevent loss of funds.

Assessed type

Error

c4-judge commented 1 year ago

Picodes marked the issue as unsatisfactory: Invalid