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

Attacker can exploit replay vulnerability to drain funds from `Starklane` bridge (`Starklane::depositTokens`)

Summary

Vulnerability Detail

The Starklane contract serves as a bridge between Ethereum and Starknet, allowing users to transfer tokens between the two networks. The depositTokens() function is a critical component of this bridge, enabling users to deposit tokens into escrow and initiate a transfer to Starknet.

The function takes several parameters:

  • salt: A value used to generate a unique request hash

  • collectionL1: Address of the token collection contract on Ethereum

  • ownerL2: Address of the new owner on Starknet

  • ids: Array of token IDs to be transferred

  • useAutoBurn: A flag to determine if tokens should be automatically burned

The function generates a request hash using these parameters and processes the deposit. However, a critical vulnerability exists in the implementation: the request hash is not stored or checked against previous requests. This oversight allows for potential replay attacks.

The root cause of this issue lies in the following code section:

req.hash = Protocol.requestHash(salt, collectionL1, ownerL2, ids);
// TODO: store request hash in storage to avoid replay attack.
// or can it be safe to use block timestamp? Not sure as
// several tx may have the exact same block.

As indicated by the TODO comment, the contract fails to implement a crucial security measure: storing and checking the request hash to prevent replay attacks.

Impact

This issue allows an attacker to replay deposit transactions, potentially draining funds from the bridge. By repeatedly submitting the same deposit request, an attacker could transfer the same tokens multiple times, creating discrepancies between the actual token balances and the bridge's recorded state.

Proof of Concept

  1. Alice initiates a legitimate deposit of 10 valuable NFTs by calling depositTokens() with a specific set of parameters.

  2. The bridge processes Alice's request, moving her NFTs into escrow and initiating the transfer to Starknet.

  3. An attacker observes this transaction and captures the parameters used.

  4. The attacker calls depositTokens() with the exact same parameters used in Alice's transaction.

  5. Due to the lack of request hash verification, the bridge processes this replayed request as if it were a new, legitimate deposit.

  6. The attacker repeats step 4 multiple times, each time causing the bridge to record a new deposit of Alice's NFTs without actually moving any additional tokens.

  7. On the Starknet side, multiple deposit events are recorded for the same NFTs, potentially allowing the attacker to withdraw more NFTs than were originally deposited.

Tools Used

Manual review

Recommendation

To mitigate this vulnerability, implement a system to track and verify request hashes. This can be achieved by adding a mapping to store processed request hashes and checking against this mapping before processing any deposit request.

Here's a suggested fix:

// Add this mapping to the contract's state variables
mapping(bytes32 => bool) private _processedRequests;
function depositTokens(
uint256 salt,
address collectionL1,
snaddress ownerL2,
uint256[] calldata ids,
bool useAutoBurn
)
external
payable
{
// ... existing code ...
Request memory req;
req.header = Protocol.requestHeaderV1(ctype, useAutoBurn, false);
req.hash = Protocol.requestHash(salt, collectionL1, ownerL2, ids);
// Check if the request hash has already been processed
require(!_processedRequests[req.hash], "Request already processed");
// Mark the request hash as processed
_processedRequests[req.hash] = true;
// ... rest of the existing code ...
}
Updates

Lead Judging Commences

n0kto Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

invalid-replay-attack-hash-not-stored-nonce-not-used

There is no impact here: Transaction cannot be replayed because the blockchain use the nonce in the signature. Hash is computed on-chain. Using or trying to have the same hash mean you need to buy the token, and they will be sent to their origin owner. Why an attacker would buy tokens to give them back ? No real impact.

Support

FAQs

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