Describe the normal behavior in one or more sentences
Normally, the Ownable2Step
contract ensures that only a trusted deployer (usually msg.sender
) becomes the initial owner, allowing them to control access-restricted functions.
Explain the specific issue or problem in one or more sentences
In this contract, ownership is not properly initialized in the constructor. The call to Ownable(msg.sender)
is invalid because Ownable2Step
does not accept constructor arguments. As a result, ownership remains unset, and any attacker can call transferOwnership()
to become the owner, then set the festival contract and mint unlimited BEAT tokens.
Likelihood:
Reason 1 // Describe WHEN this will occur (avoid using "if" statements)
This will occur on deployment since Ownable2Step
does not accept constructor arguments to set the initial owner.
Reason 2
No _transferOwnership()
call is made, so the contract has no owner from the start.
Impact:
Impact 1
Any user can call setFestivalContract()
and take full control of BEAT token minting and burning.
Impact 2
This compromises the integrity of the token ecosystem, allowing unrestricted inflation or denial-of-service via unauthorized burns.
This Proof of Concept (PoC) showing how any attacker can become the owner
and take over the setFestivalContract()
function:
Upon deployment, the contract has no owner set, leaving owner()
as the zero address. This allows anyone to call setFestivalContract()
and assign themselves as the authorized festival contract. With that, they gain unrestricted access to mint()
and burnFrom()
, enabling them to freely mint BEAT tokens to any address, including their own.
This ensures the Ownable2Step
parent contract’s owner
is correctly initialized, preventing unauthorized access to setFestivalContract()
and any future owner-restricted functions.
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.