The RootUpgrade library’s initializeRootUpgrade
function performs a delegatecall to contracts listed in the initializables
array without verifying their integrity. This design grants untrusted code execution privileges and completely compromises the calling contract’s logic.
The initializeRootUpgrade
function references an array of “initializables” and uses Address.functionDelegateCall
on each contract within this array. The function does not validate or limit the trustworthiness of the addresses it calls.
This design violates fundamental security guarantees by allowing unvetted contracts to run code with the deployer’s context. Attackers can insert a malicious contract into the initializables
array, causing the protocol to execute arbitrary code during the upgrade process. This approach bypasses normal function access restrictions because delegatecall
executes in the state context of the calling contract.
High
Attackers gain complete control over the caller’s state, enabling them to rewrite contract variables, re-route funds, or perform any operation that the contract owner can execute.
The vulnerability materializes whenever an untrusted or malicious contract address appears in the initializables
array. If no strict governance or whitelisting process exists to lock down these addresses, the scenario inevitably arises under any compromised or careless upgrade procedure.
An attacker deploys a contract named MaliciousInit
with destructive logic in its fallback function.
The attacker or a compromised admin includes the attacker’s contract address in the initializables
array.
Upon calling initializeRootUpgrade
, the protocol executes delegatecall
to MaliciousInit
under the privileges of the RootUpgrade context, enabling unauthorized modifications to protocol state.
When MaliciousInit
is delegate-called, its fallback()
executes within the storage context of RootUpgrade
. The malicious assembly code overwrites storage slot 0 with 0xDEADBEEF
(or performs any other destructive action, such as transferring funds or setting an owner to a new address).
The attacker manipulates the state variables of the calling contract. They can reset ownership, drain tokens, or otherwise compromise the protocol’s logic.
Enforce strict validation on each address in the initializables
array:
Use a governance-approved list of verified contracts or a whitelisted registry. This measure ensures only vetted logic can execute delegatecalls, blocking malicious code from hijacking the upgrade process.
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.