The summary of the below detail is that the low-level calls bypass type checking, function existence check, and argument packing and due to the fact that the EVM considers a call to a non-existing contract to always succeed makes the below-mentioned code vulnerable.
BridgeReth.sol - Line 98 - 107
The unstake function of the BridgeReth contract after burning the rocketETHToken and validating the netBalance calls the to contract using the low-level call and checks only the sent state of it.
This is unsafe because the low-level calls return true for all non-existing contract addresses.
Note: This function also does not have any check for address(0) but a non-existing contract can be a non-zero address.
low-level callsYou should avoid using .call() whenever possible when executing another contract function as it bypasses type checking, function existence check, and argument packing.
Due to the fact that the EVM considers a call to a non-existing contract to always succeed, Solidity includes an extra check using the extcodesize opcode when performing external calls. This ensures that the contract that is about to be called either actually exists (it contains code) or an exception is raised. The low-level calls which operate on addresses rather than contract instances (i.e. .call(), .delegatecall(), .staticcall(), .send() and .transfer()) do not include this check, which makes them cheaper in terms of gas but also less safe.
Solidity Docs - Members of Address Types
I have used this code to demonstrate, you can paste it into Remix IDE and verify it as well.
Deployed the ContractB which contains the selfdestruct function (copy the contract address for later).
Then call the destroy function of ContractB which will destroy this contract. After that, this contract will not exist anymore but its code still will be available on the blockchain.
Deploy the ContractA
Call the check function with the destroyed contract address and any msg.value.
As you can see the call went successful but the contract does not exist.
While unstaking the BridgeReth contract can accidentally lose funds by executing a call to a non-existing targe.
Manual Review
Use the Openzeppelin Address library to perform the external call.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.