Closed code423n4 closed 2 years ago
contract can always be redeployed if another address or user init's the contract.
This is a low severity issue
I'm pretty sure deployCore.sh#L17 will fail and return error, even if the attacker managed to send the init() before the script. I will downgrade this to QA
.
Lines of code
https://github.com/code-423n4/2022-03-volt/blob/f1210bf3151095e4d371c9e9d7682d9031860bbd/contracts/core/Core.sol#L20-L24
Vulnerability details
Impact
This is a standard front-runnable initializer vulnerability, but this instance in particular is very severe due to the permissions granted to the caller of
init()
incore.sol
. See code below:The
init()
function instantiates VOLT and then grants the governor role tomsg.sender
. The comment above indicates thatmsg.sender
will already have minting abilities, but if not, they would be able to call thegrantMinter()
function due to their governor permissions.Reviewing the
deployCore.sh
, it appears thatcore.sol
is deployed first, followed byGlobalRateLimitedMinter.sol
. The scripts attempts to callinit()
after deploying core, which will fail if an attacker calls it first. Eventually, when the script tries to callgrantMinter()
forGlobalRateLimitedMinter
it will fail due to lack of governor permissions.The key to the attack is that the attacker must call
grantMinter()
forGlobalRateLimitedMinter
following the deployment of this contract. This will cause the deploy script to assume that the contracts were deployed successfully, as the only check is thatisMinter(GlobalRateLimitedMinter_Address) == true
.Proof of Concept
Steps of attack:
core.sol
init()
incore.sol
, receivesgovernor
role.GlobalRateLimitedMinter.sol
grantMinter()
forGlobalRateLimitedMinter
incore.sol
, imported frompermissions.sol
deployCore.sh
does not detect that anything went wrong with the deployment due toGlobalRateLimitedMinter
minter role == true.Tools Used
Manual review.
Recommended Mitigation Steps
Add access control to
init()
. Adding an onlyOwner modifier would eliminate this risk as it seems like the intent is to callinit()
within the same deploy script as deployingcore.sol
. Havinginit()
without access control doesn't seem to add any desired functionality.