Open code423n4 opened 2 years ago
[L-01] | Apply two-step verification if _l2Receiver is not msg.sender L
[L-02] | Very critical governor privileges can cause complete destruction of the project in a possible privateKey exploit | 12 L
[L-03] | Incorrect NatSpec in deposit function for _amount | NC
[L-04] | Require messages are too short and unclear | 78 NC
[L-05] | If the _amount sent to L2 is lower than the minimum tx value, the user cannot use the fund in L2 I believe out of scope until fees are modeled.
[NC-01 ] | _withdrawFunds function create dirty bits R
[NC-02] | Insufficient coverage | NC
[NC-03] | Using Vulnerable Version of Openzeppelin | 2 R
[NC-04] | 0 address check | 2 L
[NC-05] | Function writing that does not comply with the Solidity Style Guide | All contracts NC
[NC-06] | Omissions in Events | 1 R
[NC-07] | Add parameter to Event-Emit | 2 Same as above
[NC-08] | Use a more recent version of Solidity | All contracts NC
[NC-09] | Solidity compiler optimizations can be problematic | NC [NC-10] | NatSpec is missing | 1 NC
[NC-11] | Require revert cause should be known | 7 Already awarded
[NC-12] | Open TODOs | 5 NC
[NC-13] | For modern and more readable code; update import usages | All contracts NC
[NC-14] | Use require instead of assert Disagree with specific instance
Honestly great progress from you, this is a really good report!
IMO, should be considered as high quality report!
3L 3R 9NC
GalloDaSballo marked the issue as grade-a
Summary
Low Risk Issues List
_l2Receiver
is not msg.sendergovernor
privileges can cause complete destruction of the project in a possible privateKey exploitdeposit
function for_amount
_amount
sent to L2 is lower than the minimum tx value, the user cannot use the fund in L2Total 5 issues
Non-Critical Issues List
_withdrawFunds
function create dirty bits0 address
checkFunction writing
that does not comply with theSolidity Style Guide
require
instead ofassert
Total 14 issues
Suggestions
Total 2 suggestions
[L-01] Apply two-step verification if
_l2Receiver
is not msg.sender_l2Receiver
in the deposit function is an important parameter to bridge Ether, this parameter is expected to be equal to msg.sender in most cases, but if another address is incorrectly typed (could be copy-paste errors), all funds will be lost, so you can use msg.sender for this argument. In case .sender is not equal, add an additional check, this will increase security The deposit function is the most important function of a bridge.Another L2 Project is the subject of Winturmute hack in Optimism; It was a token sent to the wrong address;
https://www.coinspeaker.com/optimism-20m-op-tokens-hackers-winterute/
[L-02] Very critical
governor
privileges can cause complete destruction of the project in a possible privateKey exploitVulnerability details
The contract’s
governor
is most important power role in this project. the governor is able to perform certain privileged activities.The
governor
is assumed to be an EOA, since the documents do not provide information on whether thegovernor
will be a multisign structure.Similar vulnerability; Private keys stolen:
Hackers have stolen cryptocurrency worth around €552 million from a blockchain project linked to the popular online game Axie Infinity, in one of the largest cryptocurrency heists on record. Security issue : PrivateKey of the project officer was stolen: https://www.euronews.com/next/2022/03/30/blockchain-network-ronin-hit-by-552-million-crypto-heist
This vulnerability can also be considered as a Rugpull risk.
Proof of Concept
governor
powers;Recommendation;
governor
can be a Multisign wallet and this part is specified in the documentation.[L-03] Incorrect NatSpec in
deposit
function for_amount
_amount
NatSpec comment indeposit
function; It is the "total amount of ether to bridge". However, the total ether amount to Bridge is msg.value and the _amount value may be less than msg.valueAlso, the difference between these two values should be prevented with a require.
[L-04] Require messages are too short and unclear
Context: L1ERC20Bridge.sol#L77, L1ERC20Bridge.sol#L117, L1ERC20Bridge.sol#L207, L1ERC20Bridge.sol#L210, L1ERC20Bridge.sol#L232, L1ERC20Bridge.sol#L249, L1ERC20Bridge.sol#L271, L1ERC20Bridge.sol#L274, L1EthBridge.sol#L93, L1EthBridge.sol#L141, L1EthBridge.sol#L166, L1EthBridge.sol#L189, L1EthBridge.sol#L205, AllowListed.sol#L15, AllowList.sol#L33, AllowList.sol#L38, AllowList.sol#L67, AllowList.sol#L100, AllowList.sol#L155, L2ContractHelper.sol#L50, L2ContractHelper.sol#L53-L54, L2ContractHelper.sol#L65-LL67, ReentrancyGuard.sol#L55, ReentrancyGuard.sol#L72, DiamondProxy.sol#L13, DiamondProxy.sol#L24, DiamondProxy.sol#L29-LL30, Base.sol#L16, Base.sol#L22, DiamondCut.sol#L23, DiamondCut.sol#L40, DiamondCut.sol#L55-L56, DiamondCut.sol#L59-L62, DiamondCut.sol#L65, DiamondCut.sol#L80, DiamondCut.sol#L94, DiamondCut.sol#L106, DiamondCut.sol#L108, DiamondCut.sol#L111-L112, Executor.sol#L28, Executor.sol#L39, Executor.sol#L41, Executor.sol#L52-L53, Executor.sol#L57-L60, Executor.sol#L117, Executor.sol#L129, Executor.sol#L136, Executor.sol#L142-L145, Executor.sol#L159, Executor.sol#L192-L195, Executor.sol#L199, Executor.sol#L216, Executor.sol#L237, Executor.sol#L241-L244, Executor.sol#L261, Executor.sol#L265, Executor.sol#L268, Executor.sol#L337, Getters.sol#L148, Governance.sol#L30, Mailbox.sol#L56, Mailbox.sol#L63, Mailbox.sol#L66, Mailbox.sol#L124, Diamond.sol#L100, Diamond.sol#L126, Diamond.sol#L135, Diamond.sol#L150, Diamond.sol#L156, Diamond.sol#L170, Diamond.sol#L176, Diamond.sol#L214, Diamond.sol#L279, Diamond.sol#L283, Diamond.sol#L287-L288, Merkle.sol#L23-L25, PriorityQueue.sol#L64, PriorityQueue.sol#L72
Description: The correct and clear error description explains to the user why the function reverts, but the error descriptions below in the project are not self-explanatory. These error descriptions are very important in the debug features of DApps like Tenderly. Error definitions should be added to the require block, not exceeding 32 bytes.
[L-05] If the
_amount
sent to L2 is lower than the minimum tx value, the user cannot use the fund in L2https://github.com/code-423n4/2022-10-zksync/blob/main/ethereum/contracts/bridge/L1EthBridge.sol#L88-L110
The 'deposit' function of the L1EthBridge.sol contract sends Ether to L2 and there is no limit amount. However, sending very small amounts of tokens will cause the balance to be unused in L2. This is a common problem in Layer2s for reasons such as airdrop, etc. For example, sending an amount of 10 wei will cause this.
1- Alice sends 20 wei from L1 to L2 2- With this amount, nothing can be done to L2 and dust remains.
Recommended Mitigation Steps
Set the min sending amount, Ex: 21000 wei
[N-01]
_withdrawFunds
function create dirty bitsThis explanation should be added in the NatSpec comments of this function that sends ether with call;
Note that this code probably isn’t secure or a good use case for assembly because a lot of memory management and security checks are bypassed. Use with caution! Some functions in this contract knowingly create dirty bits at the destination of the free memory pointer.
Recommendation: Add this comment to
_withdrawFunds
function; /// @dev Use with caution! Some functions in this contract knowingly create dirty bits at the destination of the free memory pointer. Note that this code probably isn’t secure or a good use case for assembly because a lot of memory management and security checks are bypassed.[N-02] Insufficient coverage
Description: Testing all functions is best practice in terms of security criteria.
Due to its capacity, test coverage is expected to be 100%
[N-03] Using Vulnerable Version of Openzeppelin
The package.json configuration file says that the project is using 4.6.0 of OpenZeppelin which has a vulnerability in initializers that call external contracts.
openzeppelin/contracts vulnerabilities: https://security.snyk.io/package/npm/@openzeppelin%2Fcontracts/
There is 2 instance of this issue
Recommendation: Use patched versions
[N-04]
0 address
checkContext:
Description: Also check of the address to protect the code from 0x0 address problem just in case. This is best practice or instead of suggesting that they verify address != 0x0, you could add some good NatSpec comments explaining what is valid and what is invalid and what are the implications of accidentally using an invalid address.
Recommendation: like this;
if (oracle == address(0)) revert ADDRESS_ZERO();
[N-05]
Function writing
that does not comply with theSolidity Style Guide
Context: All Contracts
Description: Order of Functions; ordering helps readers identify which functions they can call and to find the constructor and fallback definitions easier. But there are contracts in the project that do not comply with this.
https://docs.soliditylang.org/en/v0.8.17/style-guide.html
Functions should be grouped according to their visibility and ordered:
constructor receive function (if exists) fallback function (if exists) external public internal private within a grouping, place the view and pure functions last
[N-06] Omissions in Events
Throughout the codebase, events are generally emitted when sensitive changes are made to the contracts. However, some events are missing important parameters
The events should include the new value and old value where possible:
Events with no old value;
[N-07] Add parameter to Event-Emit
Some event-emit description hasn’t parameter. Add to parameter for front-end website or client app , they can has that something has happened on the blockchain.
Events with no old value;
[N-08] Use a more recent version of Solidity
Context: All contracts
Description: For security, it is best practice to use the latest Solidity version. For the security fix list in the versions; https://github.com/ethereum/solidity/blob/develop/Changelog.md
Recommendation: Old version of Solidity is used
(^0.8.0)
, newer version can be used(0.8.17)
[N-09] Solidity compiler optimizations can be problematic
Description: Protocol has enabled optional compiler optimizations in Solidity. There have been several optimization bugs with security implications. Moreover, optimizations are actively being developed. Solidity compiler optimizations are disabled by default, and it is unclear how many contracts in the wild actually use them.
Therefore, it is unclear how well they are being tested and exercised. High-severity security issues due to optimization bugs have occurred in the past. A high-severity bug in the emscripten-generated solc-js compiler used by Truffle and Remix persisted until late 2018. The fix for this bug was not reported in the Solidity CHANGELOG.
Another high-severity optimization bug resulting in incorrect bit shift results was patched in Solidity 0.5.6. More recently, another bug due to the incorrect caching of keccak256 was reported. A compiler audit of Solidity from November 2018 concluded that the optional optimizations may not be safe. It is likely that there are latent bugs related to optimization and that new bugs will be introduced due to future optimizations.
Exploit Scenario A latent or future bug in Solidity compiler optimizations—or in the Emscripten transpilation to solc-js—causes a security vulnerability in the contracts.
Recommendation: Short term, measure the gas savings from optimizations and carefully weigh them against the possibility of an optimization-related bug. Long term, monitor the development and adoption of Solidity compiler optimizations to assess their maturity.
[N-10] NatSpec is missing
Description: NatSpec is missing for the following functions , constructor and modifier:
Context:
L2ContractHelper.sol
[N-11] Require revert cause should be known
Context:
Description: Vulnerability related to description is not written to require, it must be written so that the user knows why the process is reverted.
This is an important debug analysis for programs and users that analyze transaction revert details such as Tenderly.
Recommendation:
[N-12] Open TODOs
Context:
Recommendation: Use temporary TODOs as you work on a feature, but make sure to treat them before merging. Either add a link to a proper issue in your TODO, or remove it from the code.
[N-13] For modern and more readable code; update import usages
Context: All contracts
Description: Solidity code is also cleaner in another way that might not be noticeable: the struct Point. We were importing it previously with global import but not using it. The Point struct
polluted the source code
with an unnecessary object we were not using because we did not need it. This was breaking the rule of modularity and modular programming:only import what you need
Specific imports with curly braces allow us to apply this rule better.Recommendation:
import {contract1 , contract2} from "filename.sol";
A good example from the ArtGobblers project;
[N-14] Use
require
instead ofassert
Description: Assert should not be used except for tests,
require
should be usedPrior to Solidity 0.8.0, pressing a confirm consumes the remainder of the process's available gas instead of returning it, as request()/revert() did.
assert() and ruqire(); The big difference between the two is that the
assert()
function when false, uses up all the remaining gas and reverts all the changes made. Meanwhile, arequire()
function when false, also reverts back all the changes made to the contract but does refund all the remaining gas fees we offered to pay. This is the most common Solidity function used by developers for debugging and error handling.Assertion() should be avoided even after solidity version 0.8.0, because its documentation states "The Assert function generates an error of type Panic(uint256). Code that works properly should never Panic, even on invalid external input. If this happens, you need to fix it in your contract. there's a mistake".
[S-01] Generate perfect code headers every time
Description: I recommend using header for Solidity code layout and readability
https://github.com/transmissions11/headers
[S-02] Add NatSpec comments to the variables defined in Storage
Description: I recommend adding NatSpec comments explaining the variables defined in Storage, their slots, their contents and definitions.
This improves code readability and control quality
Current Code;
Recommendation Code;