DeFiHardhat
21,000 USDC
View results
Submission Details
Severity: high
Invalid

Forged Merkle Proofs can be submitted

Summary

Without the length check, the contract may accept Merkle proofs of incorrect lengths. This could allow attackers to exploit vulnerabilities in the verification process and claim tokens with invalid or forged proofs.

Vulnerability Details

In the following function there is no verification of the lengnth of the merkle proof. Allowing attackers to submit invalid proofs or forged proofs of varying lengths.

function pick(
address token,
uint256 amount,
bytes32[] memory proof,
LibTransfer.To mode
) external payable nonReentrant {
bytes32 root = s.u[token].merkleRoot;
require(root != bytes32(0), "UnripeClaim: invalid token");
require(!picked(msg.sender, token), "UnripeClaim: already picked");
bytes32 leaf = keccak256(abi.encodePacked(msg.sender, amount));
require(MerkleProof.verify(proof, root, leaf), "UnripeClaim: invalid proof");
s.unripeClaimed[token][msg.sender] = true;
LibTransfer.sendToken(IERC20(token), amount, msg.sender, mode);
emit Pick(msg.sender, token, amount);
}

Impact

Function can allow forged proofs submitted that can potentially lead to loss of funds.
Potential Denial-of-Service (DoS), an attacker could submit a very large or malformed proof to consume gas and block execution.

Tools Used

Manual Review

Recommendations

Introduce a check to verify length of the merkle proof:

function pick(
address token,
uint256 amount,
bytes32[] memory proof,
LibTransfer.To mode
) external payable nonReentrant {
bytes32 root = s.u[token].merkleRoot;
require(root != bytes32(0), "UnripeClaim: invalid token");
require(!picked(msg.sender, token), "UnripeClaim: already picked");
bytes32 leaf = keccak256(abi.encodePacked(msg.sender, amount));
// Calculate the expected length of the proof array based on the Merkle tree height
uint256 expectedProofLength = calculateExpectedProofLength();
// Check if the actual length of the proof array matches the expected length
require(proof.length == expectedProofLength, "UnripeClaim: invalid proof length");
// Verify the Merkle proof
require(MerkleProof.verify(proof, root, leaf), "UnripeClaim: invalid proof");
s.unripeClaimed[token][msg.sender] = true;
LibTransfer.sendToken(IERC20(token), amount, msg.sender, mode);
emit Pick(msg.sender, token, amount);
}

and a function that handles the calculation of expected proof.

function calculateExpectedProofLength(bytes32[] memory proof) internal pure returns (bool) {
uint256 len = proof.length;
// Minimum proof length is 1 (root)
if (len < 1) {
return false;
}
// Adjust the maximum length based on your Merkle tree depth
// This value can be a constant or configurable variable
uint256 maxLength = 256;
if (len > maxLength) {
return false;
}
return true;
}
Updates

Lead Judging Commences

giovannidisiena Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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