Sablier

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

Reorg attack when create merkleLL and merkleLT

Vulnerability Details

In SablierV2MerkleLockupFactory contract, function createMerkleLL() and createMerkleLT() use CREATE1 to create contract:
Function createMerkleLL():

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():

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);
}

Attack scenario:
. User vsll createMerkleLT() to create contract
. User deposit token to that contract (to make other user to able to claim them)
. reorg happen
. Attacker call createMerkleLT(), receive token sent by user and withdraw them

Impact

When reorg happen, user's token is stolen by attacker

Tools Used

Manual review

Recommendations

Using CREATE2 with salt is created by caller

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.