This repository has been archived by the owner on Oct 6, 2024. It is now read-only.
Trust - Anyone can freeze future withdrawals and any L2->L1 messaging due to mismatch between the VM-viewed block number and the user supplied block number. #206
Labels
Duplicate
A valid issue that is a duplicate of an issue with `Has Duplicates` label
Medium
A valid Medium severity issue
Reward
A payout will be made for this issue
Sponsor Confirmed
The sponsor acknowledged this issue is valid
Won't Fix
The sponsor confirmed this issue will not be fixed
Trust
high
Anyone can freeze future withdrawals and any L2->L1 messaging due to mismatch between the VM-viewed block number and the user supplied block number.
Summary
Anyone can freeze future withdrawals and any L2->L1 messaging due to mismatch between the VM-viewed block number and the user supplied block number.
Vulnerability Detail
When a game is created, the proposer passed the L2 block number. It is stored as the third Clone parameter:
If a game is defended correctly, the anchor will use this function to commit a trusted OutputRoot:
This root can at that point be used by proofs.
Note that if the
l2BlockNumber()
is not fresh, meaning we have a root for a later block number, the anchor state is not updated:Thus, if it was possible to prove an honest root for a dishonest
l2BlockNumber
, an attacker could choose a block number far in the future and make it the anchor. From that point, all true proofs will suffer from the early return and won't update the rootClaim. Thus, any new withdrawals will not be accepted (they are not part of the trusted root).In fact, this is exactly the case, there is no limit to how large the passed
blockNumber
is. On Game creation, it just checks it is not smaller than the already trusted root:Furthermore, this parameter is invisible in the eyes of the Fault Proof VM. In
addLocalData()
, we can see which inputs are sent to the VM for processing.The global block number is never passed. The VM is only concerned with the disputed block number, which it calculates from the anchor block number and the trace index of the disputed position. That's insufficient, because the traceIndex() calculates on an assumed block number according to the game depth.
This has been also separately verified with the sponsor, to ensure that no extra details were missed.
The attack path is therefore:
l2BlockNumber
Impact
Anyone can freeze future withdrawals and any L2->L1 messaging.
Code Snippet
Tool used
Manual Review
Recommendation
The
l2BlockNumber
passed should be santized to line with the block number calculated by the VM.Duplicate of #90
The text was updated successfully, but these errors were encountered: