Flow

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

Stream NFT Transferability Control Manipulation

Summary

Stream creation function allows arbitrary callers to permanently set NFT transferability flag on behalf of legitimate sender. This can break intended NFT functionality for the sender and affect protocol integrations expecting specific transferability status.

Vulnerability Details

Relavant code. 1
2

In SablierFlow.sol, the create function allows any address to create streams:

function create(
address sender,
address recipient,
UD21x18 ratePerSecond,
IERC20 token,
bool transferable
) external returns (uint256 streamId) {
if (sender == address(0)) {
revert Errors.SablierFlow_SenderZeroAddress();
}
// Creates stream with transferability flag set by msg.sender
_streams[streamId] = Flow.Stream({
isTransferable: transferable, // Can never be modified after creation
sender: sender,
...
});
}

create and createAndDeposit functions lacks of access control, which allows anyone to create flow streams on the behalf of legitimate sender. Issues arises due to immutable status of nft transferability flag set by the caller.


Breaks sender's intended NFT functionality

  • If sender wanted transferable NFT: Attacker can make it non-transferable by front running his transaction.

  • If sender wanted non-transferable NFT: Attacker can make it transferable by front running his transaction.

  • Affects protocol integrations expecting specific transferability

  • Could impact:

    • NFT marketplace integrations

    • Using stream NFTs as collateral

    • Token-gated access systems

    • Protocol's composability

Impact

Although funds are directly not at risk, but it breaks the core funcationality of NFT integration / usage. NFTs that are meant to be used a collateral, can't be used to opposite transfer flag set by malicious actor.

Similary if NFT is meant to be non-trasferable by original sender, due to Malicious actor front running it's transferrable, that breaks the token-gated system. As same token id can be used by multiple users.

Tools Used

Manual Review

Recommendations

Flow stream, must be created by the original sender, in order to avoid this issue.

function create(...) external {
+ if (msg.sender != sender) {
+ revert Errors.Unauthorized(sender, msg.sender);
+ }
...
}

similarly update createAndDeposit

function createAndDeposit(
address sender,
address recipient,
UD21x18 ratePerSecond,
IERC20 token,
bool transferable,
uint128 amount
)
external
override
noDelegateCall
returns (uint256 streamId)
{
// Checks, Effects, and Interactions: create the stream.
+ if (msg.sender != sender) {
+ revert Errors.Unauthorized(sender, msg.sender);
+ }
streamId = _create(sender, recipient, ratePerSecond, token, transferable);
// Checks, Effects, and Interactions: deposit on stream.
_deposit(streamId, amount);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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