NFTBridge
60,000 USDC
View results
Submission Details
Severity: high
Invalid

Race Condition in Request Cancellation Process

Summary

The startRequestCancellation function in the Starklane bridge contract is vulnerable to a race condition. An attacker could potentially exploit this vulnerability by calling the withdrawTokens function with the same request payload before the cancellation process is completed, leading to potential double-spending or unauthorized token withdrawals.

Vulnerability Details

The startRequestCancellation function initiates the cancellation of a L1 to L2 message but does not immediately prevent the associated tokens from being withdrawn. There's a time window between starting the cancellation and finalizing it where the same request could still be processed by the withdrawTokens function.

function startRequestCancellation(
uint256[] memory payload,
uint256 nonce
) external onlyOwner {
IStarknetMessaging(_starknetCoreAddress).startL1ToL2MessageCancellation(
snaddress.unwrap(_starklaneL2Address),
felt252.unwrap(_starklaneL2Selector),
payload,
nonce
);
Request memory req = Protocol.requestDeserialize(payload, 0);
emit CancelRequestStarted(req.hash, block.timestamp);
}

An attacker could observe the startRequestCancellation transaction in the mempool and quickly submit a withdrawTokens transaction with the same payload, potentially allowing them to withdraw tokens that were intended to be locked due to the cancellation process.

Impact

The impact of this vulnerability could be severe:

  • Double-spending: Tokens could be withdrawn even though a cancellation was initiated.

  • Unauthorized withdrawals: An attacker could potentially withdraw tokens they shouldn't have access to.

  • Inconsistent state: The L1 and L2 states could become inconsistent if a withdrawal succeeds after a cancellation is initiated.

Tools Used

Manual

Recommendations

To mitigate this vulnerability, consider implementing the following changes:

  • Implement a locking mechanism:

  1. Add a mapping to track cancellation requests: mapping(bytes32 => bool) private _cancellationRequests;

  2. In startRequestCancellation, set the request as being cancelled: _cancellationRequests[req.hash] = true;

  3. In withdrawTokens, check if the request is being cancelled and revert if so:

if (_cancellationRequests[req.hash]) {
revert RequestBeingCancelled();
}
  • Combine cancellation initiation and finalization: If possible, modify the protocol to allow for atomic cancellation, eliminating the time window between initiation and finalization.

  • Implement a timelock:
    Add a timelock period after startRequestCancellation during which withdrawTokens cannot be called for the same request.

Updates

Lead Judging Commences

n0kto 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.