Sablier

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

Users of account abstraction wallets may lose tokens due to different addresses across chains

Summary

When deploying instances of streams across various chains, users with account abstraction wallets have different addresses across different chains for the same account.
Consequently, if all tokens are claimed for someone using an account abstraction wallet, the tokens will be sent to the wrong address and lost permanently. Additionally, a malicious attacker who notices this could perform griefing attacks on all account abstraction wallet users by voluntarily executing claim()
for these users.

Vulnerability Details

With the potential for millions of users and substantial assets involved, there is a significant risk that claim rewards could be called for account abstraction wallet users, resulting in the loss of tokens.

Account abstraction wallets can have different addresses across different chains. When a user with such a wallet attempts to claim rewards on multiple chains, the address used may differ between chains.
If the contract logic assumes the same address across all chains, this discrepancy can lead to lost tokens.

In the claim function, the recipient's address is used directly to create the stream.

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. Hashing twice prevents second preimage attacks.
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);
}

Here, the function passes the recipient's address directly to create the stream. This address is assumed to be the same across all EVM-compatible chains, which is not the case for account abstraction wallets.

Impact

If all rewards are claimed for someone using an account abstraction wallet, the will tokens sent to the wrong address and lost permanently. Moreover, a malicious attacker who notices this discrepancy could perform griefing attacks on all account abstraction wallet users by voluntarily executing claim()
for these users, resulting in the permanent loss of their tokens.

Tools Used

Manual Review

Recommendations

Provide users with the option to specify the address where rewards should be sent on each chain.
This can be achieved by adding an extra address variable to the user data structure, ensuring that users can set their recipient address correctly.

struct UserData {
uint128 lastStake;
uint256 deposited;
uint256 rate;
uint256 pendingRewards;
address l2recipient; // Additional address field for specifying the recipient address on another chain
}

Clearly warn users with account abstraction wallets to specify different addresses for each chain to avoid loss of tokens.

Updates

Lead Judging Commences

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.