Summary
The SablierFlow::create
function allows any user to create a streams, but the SablierFlow::_create
function only checks if the sender's address is not a zero address. It doesn't verify if the recipient's address is a zero address, meaning users could accidentally input a zero address instead of the intended recipient.
Vulnerability Details
If a sender decides to create a stream using the SablierFlow::create
, SablierFlow::createAndDeposit
functions and enters all the required details, but accidentally inputs the zero address as the recipient, it could lead to a poor user experience and unintentional loss of funds
function _create(
address sender,
address recipient,
UD21x18 ratePerSecond,
IERC20 token,
bool transferable
)
internal
returns (uint256 streamId)
{
if (sender == address(0)) {
revert Errors.SablierFlow_SenderZeroAddress();
}
@audit No validation check for recipient address
uint8 tokenDecimals = IERC20Metadata(address(token)).decimals();
if (tokenDecimals > 18) {
revert Errors.SablierFlow_InvalidTokenDecimals(address(token));
}
streamId = nextStreamId;
_streams[streamId] = Flow.Stream({
balance: 0,
isStream: true,
isTransferable: transferable,
isVoided: false,
ratePerSecond: ratePerSecond,
sender: sender,
snapshotDebtScaled: 0,
snapshotTime: uint40(block.timestamp),
token: token,
tokenDecimals: tokenDecimals
});
unchecked {
nextStreamId = streamId + 1;
}
_mint({ to: recipient, tokenId: streamId });
emit ISablierFlow.CreateFlowStream({
streamId: streamId,
sender: sender,
recipient: recipient,
ratePerSecond: ratePerSecond,
token: token,
transferable: transferable
});
}
In this scenario:
The sender creates the stream and passes the zero address check in the internal Sablier::_create
function.
The sender provides all the necessary inputs to initiate the stream.
The sender mistakenly enters the zero address as the recipient.
As a result, the sender may unintentionally send funds to the zero address, thinking they are sending them to the intended recipient.
Impact
It can lead to unintentional loss of funds
Tools Used
Manuel review
Recommendations
Include a validation check that checks for address zero for the recipient address and also include the error message in the Errors.sol as SablierFlow_RecipientZeroAddress
function _create(
address sender,
address recipient,
UD21x18 ratePerSecond,
IERC20 token,
bool transferable
)
internal
returns (uint256 streamId)
{
if (sender == address(0)) {
revert Errors.SablierFlow_SenderZeroAddress();
}
+ if (recipient == address(0)) {
revert Errors.SablierFlow_RecipientZeroAddress();
}
uint8 tokenDecimals = IERC20Metadata(address(token)).decimals();
if (tokenDecimals > 18) {
revert Errors.SablierFlow_InvalidTokenDecimals(address(token));
}
streamId = nextStreamId;
_streams[streamId] = Flow.Stream({
balance: 0,
isStream: true,
isTransferable: transferable,
isVoided: false,
ratePerSecond: ratePerSecond,
sender: sender,
snapshotDebtScaled: 0,
snapshotTime: uint40(block.timestamp),
token: token,
tokenDecimals: tokenDecimals
});
unchecked {
nextStreamId = streamId + 1;
}
_mint({ to: recipient, tokenId: streamId });
emit ISablierFlow.CreateFlowStream({
streamId: streamId,
sender: sender,
recipient: recipient,
ratePerSecond: ratePerSecond,
token: token,
transferable: transferable
});
}