When msg.sender, who is neither the stream's recipient nor the recipient's approved spender, calls the SablierV2Lockup.withdraw function with the recipient's address as the to input, the recipient can be forced to withdraw from such stream without the recipient's consent. If the recipient or sender is a contract that implements the onLockupStreamWithdrawn function, such onLockupStreamWithdrawn function can be called unexpectedly and adversely, such as causing the recipient to withdraw much earlier than intended and fail to become more vested coercively.
When msg.sender is neither the stream's recipient nor such recipient's approved spender, calling the following SablierV2Lockup.withdraw function with such recipient's address as the to input would not revert with Errors.SablierV2Lockup_WithdrawalAddressNotRecipient because to != recipient is false. This causes the withdraw function to be called without the consent of the stream's recipient. In this case, if the stream's recipient or sender is a contract that implements the onLockupStreamWithdrawn function, the ISablierV2Recipient(recipient).onLockupStreamWithdrawn or ISablierV2Sender(sender).onLockupStreamWithdrawn function would be called, which can be unexpected and adverse to such recipient.
https://github.com/Cyfrin/2024-05-Sablier/blob/1fe69e059dcbd71728bdfaa58dad85ff199ee6dc/v2-core/src/abstracts/SablierV2Lockup.sol#L332-L402
For example, for incentivizing the recipient to not withdraw early, the stream's sender represented by a contract and recipient could agree on a vesting scheme that only allows the recipient to withdraw once in which the sender's onLockupStreamWithdrawn function would call the SablierV2Lockup.cancel function to cancel the corresponding stream and refund its unvested amount to the sender immediately after the withdraw function is called for such stream. When someone, who is not the stream's recipient, calls the withdraw function with the recipient's address as the to input after just a small stream amount has become vested, the sender's onLockupStreamWithdrawn function would be called. In this situation, the recipient fails to become more vested and cannot withdraw more stream amount even though she or he does not intend to withdraw early at all.
Manual Review
https://github.com/Cyfrin/2024-05-Sablier/blob/1fe69e059dcbd71728bdfaa58dad85ff199ee6dc/v2-core/src/abstracts/SablierV2Lockup.sol#L363-L365 can be updated to the following code.
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.