Flow

Sablier
FoundryDeFi
20,000 USDC
View results
Submission Details
Severity: high
Invalid

SablierFlowBase.recover(IERC20,address) (src/abstracts/SablierFlowBase.sol#244-258) uses a dangerous strict equality: - surplus == 0 (src/abstracts/SablierFlowBase.sol#248)

Summary : The recover function in the SablierFlowBase contract is designed to recover a surplus of tokens from the contract. The function takes two parameters:

  • token: The token to recover.

  • to: The address to which the tokens should be transferred.

The function calculates the surplus of tokens by subtracting the aggregate balance from the token balance:

uint256 surplus = token.balanceOf(address(this)) - aggregateBalance[token];

The function then uses a strict equality comparison (==) to check if the surplus is equal to 0:

`if (surplus == 0) { // Revert if the surplus is 0 }`

This comparison is used to prevent recoveries of 0 tokens, which would be unnecessary and potentially wasteful.

Vulnerability Details : The use of a strict equality comparison (==) can be problematic. In Solidity, the == operator checks for exact equality between two values. This means that if the surplus is very close to 0, but not exactly equal, the comparison will return false.

For example, suppose the surplus is calculated to be 0.000001 due to a precision issue. In this case, the strict equality comparison (==) will return false, even though the value is essentially 0.

Impact :

This can lead to incorrect behavior in the contract, including:

  • Incorrect recoveries: The contract may allow recoveries of amounts that are very close to 0 but not exactly equal.

  • Reverts: The contract may revert when attempting to recover an amount that is very close to 0 but not exactly equal.

Example:

Suppose the surplus is calculated to be 0.000001 due to a precision issue. In this case, the strict equality comparison (==) will return false, even though the value is essentially 0.

if (surplus == 0) { // This code will not be executed even though surplus is essentially 0 }

Proof of Concept Code : Here is a proof of concept code that demonstrates the vulnerability:

contract ExploitContract {
SablierFlowBase public sablierFlowBase;
constructor(address sablierFlowBaseAddress) public {
sablierFlowBase = SablierFlowBase(sablierFlowBaseAddress);
}
function exploit() public {
// Set the surplus variable to a value very close to 0
uint256 surplus = 0.000001;
// Set the token and to variables
IERC20 token = IERC20(0x...); // Replace with the actual token address
address to = address(this);
// Call the recover function with the surplus value
sablierFlowBase.recover(token, to);
// Check if the contract behaved incorrectly
require(sablierFlowBase.balanceOf(token) != surplus, "Contract behaved correctly");
}
}

This code creates a new contract called ExploitContract that has a reference to the SablierFlowBase contract. The exploit function sets the surplus variable to a value very close to 0 and then calls the recover function with that value.

The require statement checks if the contract behaved incorrectly by verifying that the balance of the token is not equal to the surplus value. If the contract behaved correctly, the require statement will throw an exception.

Tools Used : VS code

Recommendations : To fix this issue, it's recommended to use a more robust comparison method, such as >= or <=, to account for potential precision issues or small differences between the values being compared.

Updated Code:

if (surplus <= 0) { // This code will be executed even though surplus is not exactly 0 }

By using a more robust comparison method, the contract can ensure that the comparison is accurate even in the presence of precision issues or small differences between the values being compared.

Updates

Lead Judging Commences

inallhonesty Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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