The Starklane
contract, which serves as a bridge between Ethereum and Starknet, contains a critical vulnerability in its withdrawTokens()
function. This function interacts with the StarklaneEscrow
contract's _withdrawFromEscrow()
function to facilitate token withdrawals. The issue lies in the order of operations within _withdrawFromEscrow()
, where the token transfer occurs before the escrow state is updated, creating a reentrancy vulnerability.
The withdrawTokens()
function in Starklane
is responsible for processing withdrawal requests from Starknet. It deserializes the request, verifies collection addresses, and calls _withdrawFromEscrow()
for each token to be withdrawn. The _withdrawFromEscrow()
function in StarklaneEscrow
performs the following steps:
Checks if the token is in escrow
Transfers the token using safeTransferFrom()
Updates the escrow state
The main flaw is that the state update occurs after the token transfer. This sequence allows a malicious contract to reenter the withdrawTokens()
function before the escrow state is updated, potentially withdrawing the same token multiple times.
Relevant code snippets:
An attacker can exploit this reentrancy vulnerability to drain multiple tokens from the escrow by repeatedly calling withdrawTokens()
before the state is updated. This can lead to a significant loss of tokens from the escrow, undermining the security and integrity of the bridge.
Attacker deploys a malicious contract with a fallback function that calls Starklane.withdrawTokens()
.
Attacker initiates a legitimate withdrawal through Starklane.withdrawTokens()
.
StarklaneEscrow._withdrawFromEscrow()
is called and transfers the token to the attacker's contract.
The attacker's fallback function is triggered, calling withdrawTokens()
again before the escrow state is updated.
Steps 3-4 repeat until the attacker has drained desired tokens from the escrow.
Manual review
To mitigate this issue, implement the following changes:
Update the escrow state before transferring tokens in _withdrawFromEscrow()
.
Implement OpenZeppelin's ReentrancyGuard
in both Starklane
and StarklaneEscrow
contracts.
Here's the recommended fix for StarklaneEscrow._withdrawFromEscrow()
:
Also, add the nonReentrant
modifier to Starklane.withdrawTokens()
:
Impact: - NFT already bridged won’t be bridgeable anymore without being stuck. Likelyhood: Low. - Attackers will corrupt their own tokens, deploying a risky contract interacting with an upgradable proxy. They have to buy and sell them without real benefits, except being mean. Some really specific and rare scenario can also trigger that bug.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.