Sablier

Sablier
DeFiFoundry
53,440 USDC
View results
Submission Details
Severity: medium
Invalid

DOS blacklisted user will cause tokens to be locked in the stream forever

Summary

In scenarios where a stream is created and claimed by a recipient who subsequently becomes blacklisted, the tokens(USDC/USDT) in the stream may become locked. This creates a situation where excess tokens cannot be withdrawn because the blacklisted user is unable to receive their tokens.

This report explores the potential impact and suggests mitigation strategies to handle such situations.

Vulnerability Details

When a stream is created and claimed, if the recipient is subsequently blacklisted, the tokens intended for the recipient become inaccessible. This could lead to excess tokens being locked in the stream with no way to withdraw them.

Impact

Tokens in the stream become inaccessible once the recipient is blacklisted. The presence of excess tokens that cannot be withdrawn due to the recipient's blacklist status. Unavailable tokens represent wasted resources as they cannot be used or reclaimed.

The claim function in the SablierV2MerkleLL contract does not currently account for blacklisted users during the claim process.

function claim(uint256 index, address recipient, uint128 amount, bytes32[] calldata merkleProof)
external override returns (uint256 streamId) {
// Generate the Merkle tree leaf by hashing the corresponding parameters.
bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(index, recipient, amount))));
// Check: validate the function.
_checkClaim(index, leaf, merkleProof);
// Effect: mark the index as claimed.
_claimedBitMap.set(index);
// Interaction: create the stream via {SablierV2LockupLinear}.
streamId = LOCKUP_LINEAR.createWithDurations(
LockupLinear.CreateWithDurations({
sender: admin,
recipient: recipient,
totalAmount: amount,
asset: ASSET,
cancelable: CANCELABLE,
transferable: TRANSFERABLE,
durations: streamDurations,
broker: Broker({ account: address(0), fee: ud(0) })
})
);
// Log the claim.
emit Claim(index, recipient, amount, streamId);
}

POC

A creator initiates a stream for a recipient. The recipient successfully claims the stream.

The recipient is subsequently blacklisted.

The tokens in the stream are locked because the blacklisted user cannot receive them and there is no mechanism to reclaim or redistribute the excess tokens.

function claim(uint256 index, address recipient, uint128 amount, bytes32[] calldata merkleProof)
external override returns (uint256 streamId) {
require(!isBlacklisted(recipient), "Recipient is blacklisted");
// Generate the Merkle tree leaf by hashing the corresponding parameters.
bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(index, recipient, amount))));
// Check: validate the function.
_checkClaim(index, leaf, merkleProof);
// Effect: mark the index as claimed.
_claimedBitMap.set(index);
// Interaction: create the stream via {SablierV2LockupLinear}.
streamId = LOCKUP_LINEAR.createWithDurations(
LockupLinear.CreateWithDurations({
sender: admin,
recipient: recipient,
totalAmount: amount,
asset: ASSET,
cancelable: CANCELABLE,
transferable: TRANSFERABLE,
durations: streamDurations,
broker: Broker({ account: address(0), fee: ud(0) })
})
);
// Log the claim.
emit Claim(index, recipient, amount, streamId);
}

Tools Used

Manual Review

Recommendations

Implement a mechanism to reclaim or redistribute tokens if the recipient is unable to receive their tokensafter the stream has been claimed.

Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 year ago
inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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