The SablierFlow
contract has a potential vulnerability when the sender and recipient of a stream are the same address. This situation can lead to unintended or malicious exploitation of the protocol's debt-tracking and fund-handling mechanisms, such as circumventing debt obligations, abusing the void
function to escape debts, and manipulating protocol fees.
When the sender and recipient of a stream are identical, specific functions in the SablierFlow
contract behave differently. This can lead to situations where users exploit self-streams to avoid payments, manipulate protocol fees, or abuse refunds in ways that undermine the protocol's intended behavior.
Debt Forgiveness via Self-Voiding:
When sender == recipient
, the user can void an insolvent stream (where the total debt exceeds the stream balance) and thereby avoid paying the full debt. This is due to the _void
function forgiving any uncovered debt upon voiding an insolvent stream.
Infinite Withdrawals and Redepositing:
If the sender and recipient are the same, the user can repeatedly withdraw and redeposit funds. This allows the user to cycle funds within the same stream without risking the loss of any funds, potentially causing an infinite loop of withdrawals and redeposits.
Refund Manipulation:
When sender == recipient
, the sender can issue refunds to themselves, effectively paying back their own funds. This allows them to initiate and terminate streams for themselves, bypassing the intended payment streaming mechanism and undermining the debt obligations.
Fee Evasion:
With sender == recipient
, the user can exploit the protocol fee structure to minimize the protocol's revenue. They might be able to manipulate the withdrawal amounts and frequency to reduce effective fees paid to the protocol.
Consider a user who starts a self-stream (where sender
and recipient
are the same) to transfer tokens to themselves at a rate of 1 token per second.
Self-Voiding to Escape Debt:
The user funds the stream with a partial balance of 1,000 tokens. Once they accumulate more debt than this balance (e.g., 1,500 tokens in debt), they invoke the void
function. Since they control both ends of the stream, they intentionally void it, writing off the 500 tokens of uncovered debt and thereby escaping the remaining payment obligation.
Infinite Withdrawals and Redepositing:
The user begins withdrawing tokens repeatedly, taking out funds and immediately redepositing them back into the stream. Because they control both sides, there is no real loss, allowing them to infinitely loop withdrawals and redeposits, congesting the network and exploiting the fund flow.
Refunding Back to Themselves:
After depositing a large sum, they invoke the refund
function to reclaim funds they had previously deposited. Since they are both sender and recipient, they can abuse this to cycle funds and reset the debt, undermining the protocol’s debt enforcement mechanism.
Fee Evasion:
By carefully timing withdrawals, they can reduce the effective protocol fee. For example, they withdraw a minimal amount multiple times to reduce cumulative fees, or they use withdrawMax
right before the stream depletes to minimize protocol revenue.
If exploited, these issues can lead to:
Financial Loss for the Protocol: Forgiving debts, fee evasion, and refund manipulation reduce the protocol’s revenue.
Integrity Risks for Debt Tracking: If users avoid debt obligations and abuse refunds, it undermines the protocol’s debt-tracking model and impacts its reliability.
System Inefficiencies: Infinite withdrawal and redeposit loops increase gas usage and could congest the network, affecting other users.
Overall, the impact is Medium to High, as these behaviors compromise the financial and functional integrity of the protocol.
Manual Code Review: Identified logic flaws based on contextual understanding of debt handling, withdrawal, and refund mechanisms.
Scenario Testing: Evaluated potential exploits in different scenarios where sender == recipient
.
Add a check to prevent streams where the sender and recipient are the same. This prevents the user from exploiting mechanisms that require distinct participants. Modify _create(...) function at SablierFlow.sol: 578
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.