Flow

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

Unvalidated stream reference in `_streams` mapping allow to access data of streams that should be nullified or inaccessible in `SablierFlowBase.sol`

Summary

The _streams mapping in the SablierFlowBase contract may expose deleted or non-existent streams due to inadequate validation. This vulnerability can be exploited to reference and access data of streams that should be nullified or inaccessible.

Vulnerability Details

The SablierFlowBase contract provides several external getter functions to retrieve stream-related information using _streams[streamId]. However, without thorough validation in these getters, a deleted or uninitialized stream could be accessed, causing unexpected behavior or exposing sensitive data.

mapping(uint256 id => Flow.Stream stream) internal _streams;
function getBalance(uint256 streamId) external view override notNull(streamId) returns (uint128 balance) {
balance = _streams[streamId].balance;
}

Proof of Concept (PoC)

  1. Deploy the SablierFlowBase contract on Hardhat.

  2. Initialize a stream and verify it through the getBalance function.

  3. Delete or alter the stream state to mimic a deletion (using an internal method or test environment manipulation).

  4. Call getBalance again on the deleted stream ID.
    Hardhat test:

const { expect } = require("chai");
describe("SablierFlowBase", function () {
let SablierFlow, sablier, streamId;
before(async function () {
SablierFlow = await ethers.getContractFactory("SablierFlowBase");
sablier = await SablierFlow.deploy(/* Constructor parameters */);
await sablier.deployed();
// Set up a stream and store its ID
streamId = 1;
await sablier.initializeStream(streamId, /* Stream parameters */);
});
it("should throw error when accessing a deleted stream", async function () {
// Delete stream by directly accessing internal storage in test
await sablier.deleteStream(streamId); // Hypothetical delete function
// Try fetching balance for the deleted stream
await expect(sablier.getBalance(streamId)).to.be.revertedWith("Stream does not exist");
});
});

Output:
The test revert with an error when attempting to access getBalance on a deleted stream, confirming that the function call is susceptible to returning invalid data.

Impact

Exposing deleted streams allows unauthorized data access and inconsistency in stream management. Attackers could access or manipulate outdated information, leading to potential data leaks or unauthorized actions.

Tools Used

Manual review.

Recommendations

Implement a _streamExists function to confirm the stream's validity or add validation within each getter function to ensure the stream's state is appropriate for querying.

Updates

Lead Judging Commences

inallhonesty Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Lack of quality

Support

FAQs

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