Platform: Code4rena
Start Date: 28/10/2022
Pot Size: $165,500 USDC
Total HM: 2
Participants: 24
Period: 12 days
Judge: GalloDaSballo
Total Solo HM: 1
Id: 177
League: ETH
Rank: 2/24
Findings: 2
Award: $34,676.26
🌟 Selected for report: 2
🚀 Solo Findings: 0
🌟 Selected for report: HE1M
Also found by: codehacker
31943.2548 USDC - $31,943.25
https://github.com/code-423n4/2022-10-zksync/blob/4db6c596931a291b17a4e0e2929adf810a4a0eed/ethereum/contracts/zksync/facets/DiamondCut.sol#L46 https://github.com/code-423n4/2022-10-zksync/blob/4db6c596931a291b17a4e0e2929adf810a4a0eed/ethereum/contracts/zksync/libraries/Diamond.sol#L277
When the governor proposes a diamondCut, governor must wait for upgradeNoticePeriod
to be passed, or security council members have to approve the proposal to bypass the notice period, so that the governor can execute the proposal.
require(approvedBySecurityCouncil || upgradeNoticePeriodPassed, "a6"); // notice period should expire require(approvedBySecurityCouncil || !diamondStorage.isFrozen, "f3");
If the governor's key is leaked and noticed by zkSync, the attacker must wait for the notice period to execute the already proposed diamondCut with the malicious _calldata
based on the note below from zkSync, or to propose a new malicious diamondCut. For, both cases, the attacker loses time.
NOTE: proposeDiamondCut - commits data associated with an upgrade but does not execute it. While the upgrade is associated with facetCuts and (address _initAddress, bytes _calldata) the upgrade will be committed to the facetCuts and _initAddress. This is done on purpose, to leave some freedom to the governor to change calldata for the upgrade between proposing and executing it.
Since, there is a notice period (as zkSync noticed the key leakage, security council member will not approve the proposal, so bypassing the notice period is not possible), there is enough time for zkSync to apply security measures (pausing any deposit/withdraw, reporting in media to not execute any transaction in zkSync, and so on).
But, the attacker can be smarter, just before the proposal be executed by the governor (i.e. the notice period is passed or security council members approved it), the attacker executes the proposal earlier than governor with the malicious _calldata
. In other words, the attacker front runs the governor.
Therefore, if zkSync notices the governor's key leakage beforehand, there is enough time to protect the project. But, if zkSync does not notice the governor's key leakage, the attacker can change the _calldata
into a malicious one in the last moment so that it is not possible to protect the project.
https://github.com/code-423n4/2022-10-zksync/blob/4db6c596931a291b17a4e0e2929adf810a4a0eed/ethereum/contracts/zksync/libraries/Diamond.sol#L277 https://github.com/code-423n4/2022-10-zksync/blob/4db6c596931a291b17a4e0e2929adf810a4a0eed/ethereum/contracts/zksync/facets/DiamondCut.sol#L46
_calldata
should be included in the proposed diamondCut:
https://github.com/code-423n4/2022-10-zksync/blob/4db6c596931a291b17a4e0e2929adf810a4a0eed/ethereum/contracts/zksync/facets/DiamondCut.sol#L27
Or, at least one of the security council members should approve the _calldata
during execution of the proposal.
#0 - c4-sponsor
2022-11-22T21:36:48Z
miladpiri marked the issue as sponsor confirmed
#1 - miladpiri
2022-11-22T21:39:06Z
It is a valid issue, and the fix is going to be implemented, so we confirm the issue as medium! Thanks.
#2 - GalloDaSballo
2022-12-02T21:12:39Z
In contrast to other reports, this shows how a malicious proposal could be injected, bypassing the timelock protection, for this reason (after consulting with a second Judge), I agree with marking it a distinct finding and agree with Medium Severity
#3 - c4-judge
2022-12-02T21:12:45Z
GalloDaSballo marked the issue as selected for report
#4 - c4-judge
2022-12-02T21:36:20Z
GalloDaSballo marked the issue as primary issue
2733.0139 USDC - $2,733.01
The critical parameters in initialize(...)
are not set safely:
s.governor
should be set to msg.sender
, because a wrong governor address will result in loss of access to all other parts, and later changing the governor to the correct address._l2BootloaderBytecodeHash
should be validated like L2ContractHelper.validateBytecodeHash(_l2BootloaderBytecodeHash)
as in GovernanceFacet
_l2DefaultAccountBytecodeHash
should be validated like L2ContractHelper.validateBytecodeHash(_l2DefaultAccountBytecodeHash)
as in GovernanceFacet
https://github.com/code-423n4/2022-10-zksync/blob/4db6c596931a291b17a4e0e2929adf810a4a0eed/ethereum/contracts/zksync/DiamondInit.sol#L39 https://github.com/code-423n4/2022-10-zksync/blob/4db6c596931a291b17a4e0e2929adf810a4a0eed/ethereum/contracts/zksync/DiamondInit.sol#L58 https://github.com/code-423n4/2022-10-zksync/blob/4db6c596931a291b17a4e0e2929adf810a4a0eed/ethereum/contracts/zksync/DiamondInit.sol#L59
Better to have also approveEmergencyDiamondCutAsSecurityCouncilMemberBySignature
, in case the security council members do not have access to ethereum blockchain or in case it is needed to approve just in one transaction by batch of signatures (to bypass the notice period).
Better to have config facet, in case some update is needed in the config.sol
. Therefore, it is not necessary to redeploy the facets that imported config (like Executor
and Mailbox
)
L2_LOG_BYTES
is not correct, it should be L2_TO_L1_LOG_SERIALIZE_SIZE
https://github.com/code-423n4/2022-10-zksync/blob/456078b53a6d09636b84522ac8f3e8049e4e3af5/ethereum/contracts/zksync/Config.sol#L19
It is not needed to have modifier senderCanCallFunction
for the function deposit
in both L1ERC20Bridge
and L1ETHBridge
, because they call the function requestL2Transaction
in the MailBox
that has already such modifier.
https://github.com/code-423n4/2022-10-zksync/blob/358f38736351a8a27e325dfcb665eeba5ec02bd5/ethereum/contracts/bridge/L1EthBridge.sol#L92
https://github.com/code-423n4/2022-10-zksync/blob/358f38736351a8a27e325dfcb665eeba5ec02bd5/ethereum/contracts/zksync/facets/Mailbox.sol#L112
For each deposit of an ERC20 token, the information of the token is read and packed and sent to L2. Even if this token is used before for deposit, again this information is sent to L2, which is waste of gas. https://github.com/code-423n4/2022-10-zksync/blob/456078b53a6d09636b84522ac8f3e8049e4e3af5/ethereum/contracts/bridge/L1ERC20Bridge.sol#L164-L169 https://github.com/code-423n4/2022-10-zksync/blob/456078b53a6d09636b84522ac8f3e8049e4e3af5/ethereum/contracts/bridge/L1ERC20Bridge.sol#L155
When a block is committed, its hash will be stored in storedBlockHashes
:
https://github.com/code-423n4/2022-10-zksync/blob/358f38736351a8a27e325dfcb665eeba5ec02bd5/ethereum/contracts/zksync/facets/Executor.sol#L164
If this block is reverted, it is not removed from storedBlockHashes
:
https://github.com/code-423n4/2022-10-zksync/blob/358f38736351a8a27e325dfcb665eeba5ec02bd5/ethereum/contracts/zksync/facets/Executor.sol#L336
The vulnerability is that in the GettersFacet
, the function storedBlockHash(...)
will return the hash of a reverted block if this block number is given as its parameter, while it should return 0.
https://github.com/code-423n4/2022-10-zksync/blob/358f38736351a8a27e325dfcb665eeba5ec02bd5/ethereum/contracts/zksync/facets/Getters.sol#L86
#0 - GalloDaSballo
2022-11-24T01:29:52Z
Logically equivalent to address(0) check, L
Not sure what this means, but if it means one caller get's to approve emerengency cuts, this is a glaring security risk
Not convinced by this one either, ultimately it's called config but it's just a bunch of contact / base contract
NC
Not convinced in lack of detail, if you call contract X and contract X calls contract Y, then the check is necessary on both contracts
Unclear what you'd do and were the savings would be
See #204 L
#1 - GalloDaSballo
2022-12-02T22:20:14Z
2L 1NC
#2 - GalloDaSballo
2022-12-03T19:08:05Z
Report was pretty good, but the downgraded findings add a lot of points to this QA.
While the Warden has sent a few false positives, I think the value they offered for this contest warrants them winning the best QA report
#3 - c4-judge
2022-12-03T19:08:11Z
GalloDaSballo marked the issue as selected for report
#4 - c4-judge
2022-12-03T20:59:16Z
GalloDaSballo marked the issue as grade-a
#5 - miladpiri
2022-12-03T22:16:22Z
Thanks @GalloDaSballo for your comment, that now we are looking at this report more seriously. IMO, No.2 “approveEmergencyDiamondCutAsSecurityCouncilMemberBySignature“ can be a security issue. This is what we are now implementing to make security council members be able to approve the proposal by signature. The security issue is that in case the security council members do not have access to approve on-chain, the governor must wait for their approval to bypass the notice period. In case the proposal should be executed instantly ( in case of a critical bug in our protocol), this delay can be dangerous to our protocol. By having approval by signature, the security members can approve a proposal off-chain, and the governor can execute the instant upgrade on behalf of them by using their signatures, so all-time access to the chain is not necessary for security council members. Moreover, in case a critical proposal should be executed silently, it is necessary to be able to approve by signature. Because, the governor, in one batch transaction, proposes the proposal, and approves the upgrade on behalf of the security council members by using their signatures, and then executes the proposal. Since all the above actions are done in one transaction, there is no security risk of vulnerability leak. But, in the current structure, when the governor proposes the proposal, should wait for security members’ approval, this delay can be transparent to a malicious user to investigate the governor’s proposal, and gets a clue what the vulnerability is and then exploits the protocol. This report worths to be upgraded in terms of severity! Thanks.
#6 - miladpiri
2022-12-06T22:46:47Z
@GalloDaSballo I would like to know your idea about my comment above. Thanks!
#7 - GalloDaSballo
2022-12-06T23:57:12Z
@GalloDaSballo I would like to know your idea about my comment above. Thanks!
Thank you for your insight, I have sent the contest to triage, took note of your feedback and am sharing with other Judges and Wardens
#8 - GalloDaSballo
2022-12-08T23:52:49Z
Similarly to #48 I have shared this finding with 2 Judges and a Top warden and we all agree that this is effectively the same finding, with similar impact.
As such Low Severity is the most appropriate.
#9 - miladpiri
2022-12-09T08:20:23Z
Thanks for the follow-up!