Sablier

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

`createMerkleLL` and `createMerkleLT` are suspicious of the reorg attack

Summary

The createMerkleLL() and createMerkleLT functions deploys a new SablierV2MerkleLL and SablierV2MerkleLT contracts respectively using the CREATE, where the address derivation depends only on the SablierV2MerkleLockupFactory nonce. This implementation results in reorg attacks and loss of funds. Re-orgs can happen in all EVM chains and as confirmed the contracts will be deployed on most EVM compatible L2s including Arbitrum, etc. It is also planned to be deployed on ZKSync also.

Vulnerability Details

This is how Airstreams work:
An Airstream campaign creator deploys an instance of a campaign using CampaignFactory and transfers funds to the instance. Recipients will then claim the funds. The vulnerability lies in the fact that createMerkleLL() and createMerkleLT() use CREATE to deploy SablierV2MerkleLL and SablierV2MerkleLT instances.

function createMerkleLL(
MerkleLockup.ConstructorParams memory baseParams,
ISablierV2LockupLinear lockupLinear,
LockupLinear.Durations memory streamDurations,
uint256 aggregateAmount,
uint256 recipientCount
)
external
returns (ISablierV2MerkleLL merkleLL)
{
// Deploy the MerkleLockup contract with CREATE.
merkleLL = new SablierV2MerkleLL(baseParams, lockupLinear, streamDurations);
// Log the creation of the MerkleLockup contract, including some metadata that is not stored on-chain.
emit CreateMerkleLL(merkleLL, baseParams, lockupLinear, streamDurations, aggregateAmount, recipientCount);
}
function createMerkleLT(
MerkleLockup.ConstructorParams memory baseParams,
ISablierV2LockupTranched lockupTranched,
MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages,
uint256 aggregateAmount,
uint256 recipientCount
)
external
returns (ISablierV2MerkleLT merkleLT)
{
// Calculate the sum of percentages and durations across all tranches.
uint64 totalPercentage;
uint256 totalDuration;
for (uint256 i = 0; i < tranchesWithPercentages.length; ++i) {
uint64 percentage = tranchesWithPercentages[i].unlockPercentage.unwrap();
totalPercentage = totalPercentage + percentage;
unchecked {
// Safe to use `unchecked` because its only used in the event.
totalDuration += tranchesWithPercentages[i].duration;
}
}
// Check: the sum of percentages equals 100%.
if (totalPercentage != uUNIT) {
revert Errors.SablierV2MerkleLockupFactory_TotalPercentageNotOneHundred(totalPercentage);
}
// Deploy the MerkleLockup contract with CREATE.
merkleLT = new SablierV2MerkleLT(baseParams, lockupTranched, tranchesWithPercentages);
// Log the creation of the MerkleLockup contract, including some metadata that is not stored on-chain.
emit CreateMerkleLT(
merkleLT,
baseParams,
lockupTranched,
tranchesWithPercentages,
totalDuration,
aggregateAmount,
recipientCount
);
}

Imagine the following scenario

  1. Alice deploys a SablierV2MerkleLL instance.

  2. Alice sends funds to the deployed SablierV2MerkleLL instance.

  3. A network block reorganization (reorg) occurs.

  4. Bob notices the block reorg and calls createMerkleLL().

  5. Bob's call creates a SablierV2MerkleLL instance with an address identical to the one Alice initially sent funds to.

  6. Alice's transactions are executed post-reorg.

  7. Alice's funds are now transferred to the SablierV2MerkleLL instance controlled by Bob's campaign.

References:
This is a Medium severity issue that has been referenced from below Code4rena reports:
https://code4rena.com/reports/2023-01-rabbithole/#m-01-questfactory-is-suspicious-of-the-reorg-attack
https://code4rena.com/reports/2023-04-frankencoin#m-14-re-org-attack-in-factory

https://protos.com/polygon-hit-by-157-block-reorg-despite-hard-fork-to-reduce-reorgs/

Impact

Theft of funds from the campaign creator, and the attacker decides the recipients and admin of the campaign.

Tools Used

Manual review

Recommendations

Deploy such contracts via create2 with salt that includes msg.sender.

Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

CREATE is vulnerable to ChainReorgs

Support

FAQs

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