DeFiHardhatFoundry
250,000 USDC
View results
Submission Details
Severity: high
Invalid

Signature Replay Vulnerability in ```L2ContractMigrationFacet``` Contract

Summary

The L2ContractMigrationFacet contract is vulnerable to signature replay attacks due to the absence of a nonce in its signature verification process. This allows an attacker to reuse a valid signature multiple times, potentially leading to unauthorized actions and incorrect state changes.

Vulnerability Details

The verifySignature function in the L2ContractMigrationFacet contract uses ECDSA for signature verification but lacks a mechanism to prevent signature reuse:

function verifySignature(
address owner,
address reciever,
uint256 deadline,
bytes calldata signature
) internal view {
require(block.timestamp <= deadline, "Migration: permit expired deadline");
bytes32 structHash = keccak256(
abi.encode(REDEEM_DEPOSIT_TYPE_HASH, owner, reciever, deadline)
);
bytes32 hash = _hashTypedDataV4(structHash);
address signer = ECDSA.recover(hash, signature);
require(signer == owner, "Migration: permit invalid signature");
}

The function only checks the deadline but doesn't use a nonce or mark the signature as used after verification. This allows the same signature to be reused in multiple transactions as long as the deadline hasn't passed.

Impact

Duplicate redemption of deposits and internal balances, incorrect allocation of assets to the receiver address and as well as manipulation of account stalk and roots balances.

If we look at the redeemDepositsAndInternalBalances function:

function redeemDepositsAndInternalBalances(
address owner,
address reciever,
AccountDepositData[] calldata deposits,
AccountInternalBalance[] calldata internalBalances,
uint256 ownerRoots,
bytes32[] calldata proof,
uint256 deadline,
bytes calldata signature
) external payable fundsSafu noSupplyChange nonReentrant {
// ... (other checks)
verifySignature(owner, reciever, deadline, signature);
// Set deposits for `reciever`
uint256 accountStalk;
for (uint256 i; i < deposits.length; i++) {
accountStalk += addMigratedDepositsToAccount(reciever, deposits[i]);
}
// Set stalk for account
setStalk(reciever, accountStalk, ownerRoots);
}

An attacker could replay a valid signature, causing duplicate calls to addMigratedDepositsToAccount, potentially double-crediting deposits and repeated execution of setStalk, incorrectly increasing stalk and roots balances.

Tools Used

Manual code review

Recommendations

  1. Implement a nonce system:

    • Include a nonce in the signed message.

    • Verify and increment the nonce during signature verification.

    • Store used nonces to prevent reuse.

  2. Implement a signature invalidation mechanism:

    • Add a function to mark signatures as used after processing.

    • Check if a signature has been used before processing it.

  3. Alternatively, consider using OpenZeppelin's signature verification libraries, which often include built-in replay protection.

Updates

Lead Judging Commences

inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Replay attack vulnerability in `redeemDepositsAndInternalBalances` function - it could be replayed

Appeal created

deadrosesxyz Judge
11 months ago
inallhonesty Lead Judge
11 months ago
inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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