Flow

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

Handling Non-Existent Streams

Summary

The contract does not properly handle requests for non-existent streams, which can lead to unintended errors and potentially expose the contract to unforeseen vulnerabilities.

Finding Description

The functions that access stream data, such as getBalance, getRatePerSecond, and getStream, rely on the existence of a stream corresponding to the provided streamId. If a caller attempts to query a stream that does not exist (i.e., no entry exists in the _streams mapping for that streamId), the contract does not revert or handle this case explicitly.

This lack of handling breaks the security guarantee of consistent and predictable state management, as the contract could return incorrect data or fail silently. A malicious user could exploit this by calling these functions with arbitrary streamIds, leading to potential denial of service if error handling is not implemented correctly.

Vulnerability Details

The specific vulnerability lies in the absence of checks to confirm the existence of a stream before attempting to access its properties. The following lines from various functions illustrate the risk:

function getBalance(uint256 streamId) external view override notNull(streamId) returns (uint128 balance) {
balance = _streams[streamId].balance; // No existence check for streamId
}

If streamId does not exist in _streams, this function will revert, but without a clear error message or handling mechanism. As a result, it can lead to a poor user experience and might be leveraged to disrupt contract operation.

Impact

This issue can lead to operational failures and an unclear understanding of contract state. If users are able to submit queries for non-existent streams, they may encounter generic errors that don't inform them of the actual problem. This can cause frustration and loss of trust in the contract, as users may not be able to ascertain the validity of their actions. Additionally, it opens up the potential for misuse of the contract's functions by malicious actors.

Proof of Concept

To demonstrate this issue, one could call the getBalance function with an arbitrary streamId that has not been initialized:

contractInstance.getBalance(999); // Assuming 999 is not a valid streamId

This call will revert without a meaningful error, exposing the lack of handling for non-existent streams.

Recommendations

To address this issue, the contract should implement a check for stream existence before attempting to access its properties. A simple existence check can be added to each function that retrieves stream data. Here’s a suggested modification to the getBalance function:

Proposed Code Snippet

function getBalance(uint256 streamId) external view override returns (uint128 balance) {
// Check if the streamId exists
if (!_streams[streamId].isStream) {
revert Errors.SablierFlow_Null(streamId); // Ensure this error message exists in the Errors library
}
balance = _streams[streamId].balance;
}

This check can be integrated into all relevant getter functions, ensuring that the contract handles non-existent streams gracefully and provides clear feedback to users.

Updates

Lead Judging Commences

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

Support

FAQs

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