Note: At the judges request, this downgraded issue from the same warden has been included in this report for completeness.
In scrolls zktrie, account leaf node and storage leaf node, each has a compressed flag value which denotes whether its field cannot be represented as a field element. If not, the field element will be split into high128/low128 bit before poseidonHash the value.
The issue is in ScrollVerifierHooks::walkTree/verifyAccountState/verifyStorageValue, the compressed flag value is part of the proof provided by the prover but never checked.
In addition, the compressed flag value is also never hashed as part of the leaf hash. As a result, a prover can pass any flag value to pass the check.
In Scrolls zktrie, a compression flag is part of the required proof and is 4 bytes long. For example, in an account trie, a valid proof of leaf node contains:
NodeType (1 byte) + NodeKey( 32 byte) + CompressedFlag( 4 byte) + nonce||code size||0 (32 bytes) + balance(32 bytes) + storageRoot (32 bytes) + keccakCodeHash (32 bytes) + PoseidonCodeHash (32 bytes)
See checks in Scroll chains implementation. We can see the official scrolls zkTrie verifier explicitly checked the compressedFlag value.
https://github.com/scroll-tech/scroll-contracts/blob/2d06562f3f252ddcd3dcda8d4bdec368ffbcc21d/src/libraries/verifier/ZkTrieVerifier.sol#L164
However, in ScrollVerifierHooks.sol, the check for the compressed flag is missing. Currently, nodeType and nodeKey(keyhash) are checked in ScrollVerifierHooks::walkTree. And from nonce to posendonCodeHash (160 bytes total) are checked against leafHash in ScrollVerifierHooks::verifyAccountState.
https://github.com/code-423n4/2024-12-unruggable/blob/9e0e908a207f088dd843fcdc3e4de5fa0edd6c5c/contracts/scroll/ScrollVerifierHooks.sol#L116
https://github.com/code-423n4/2024-12-unruggable/blob/9e0e908a207f088dd843fcdc3e4de5fa0edd6c5c/contracts/scroll/ScrollVerifierHooks.sol#L53
Note that the compressed flag can be set arbitrarily in ScrollVerifier::verifyStorageValue -> walkTree flow in a similar way.
Check the flag to be the exact expected value (0x05080000,0x01010000).
raffy (Unruggable) disputed and commented:
Picodes (judge) decreased severity to Low and commented:
