Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: low
Valid

TimelockController: Emergency Bypass

Summary

The TimelockController allows privileged roles (EMERGENCY_ROLE) to bypass the timelock delay and execute arbitrary actions immediately. This violates the core purpose of a timelock—to provide users with a grace period to audit or react to sensitive changes. Attackers can exploit this to drain funds, alter governance, or disable critical protocol functions without warning.

Code Snippet

https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/governance/proposals/TimelockController.sol#L223

https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/governance/proposals/TimelockController.sol#L237

Vulnerability Details

Example Scenario :

  • An malicious actor gains EMERGENCY_ROLE as an EMERGENCY_ROLE holder

  • Schedule Malicious Action: Call scheduleEmergencyAction to queue a payload (e.g., transfer all funds to attacker’s address).

  • Execute Immediately: Call executeEmergencyAction in the same transaction, bypassing any timelock delay.

Code Proof:

In TimelockController.sol, emergency actions skip the timelock:

function scheduleEmergencyAction(bytes32 id) external onlyRole(EMERGENCY_ROLE) {
_emergencyActions[id] = true; // No delay enforced
}
function executeEmergencyAction(...) external payable onlyRole(EMERGENCY_ROLE) {
// Executes immediately without delay checks
for (uint256 i = 0; i < targets.length; i++) {
(bool success, ) = targets[i].call{value: values[i]}(calldatas[i]);
...
}
}

Attack Simulation:

  • Normal Timelock: A proposal to drain funds requires a 7-day delay.

  • Emergency Bypass:

    Actor schedules and executes transferFunds(to=attacker) in one transaction.

  • Funds are stolen instantly.

Impact

  1. The malicious Actor can drain all protocol assets.

  2. Governance Takeover: Emergency roles can replace governance contracts or parameters.

  3. Loss of Trust: Users lose confidence in the protocol’s safety mechanisms.

Tools Used

Manual review

Recommendations

Enforce a minimum emergency delay and restrict EMERGENCY_ROLE to multi-sig/DAO.

Step 1: Add Emergency Delay

// TimelockController.sol
uint256 public constant EMERGENCY_DELAY = 24 hours; // Minimum delay
mapping(bytes32 => uint256) public emergencyScheduledTime;
function scheduleEmergencyAction(bytes32 id) external onlyRole(EMERGENCY_ROLE) {
require(!_emergencyActions[id], "Action already scheduled");
emergencyScheduledTime[id] = block.timestamp;
_emergencyActions[id] = true;
emit EmergencyActionScheduled(id, block.timestamp);
}
function executeEmergencyAction(...) external payable onlyRole(EMERGENCY_ROLE) {
require(_emergencyActions[id], "Action not scheduled");
require(
block.timestamp >= emergencyScheduledTime[id] + EMERGENCY_DELAY,
"Emergency delay not met"
);
delete _emergencyActions[id];
...
}

Step 2: Restrict EMERGENCY_ROLE to Multi-Sig

// During contract deployment:
_grantRole(EMERGENCY_ROLE, multiSigAddress); // Use a 3/5 multi-sig
_revokeRole(EMERGENCY_ROLE, initialOwner); // Remove single-admin access

Step 3: Add Transparency Events

event EmergencyActionScheduled(bytes32 indexed id, uint256 scheduledTime);
event EmergencyActionExecuted(bytes32 indexed id, address executor, uint256 timestamp);Why This Fix Works

Why this fix works :

Mandatory Delay: Even emergency actions require a 24-hour delay, allowing users to react.

Multi-Sig Control: Reduces single-point-of-failure risk.

Transparency: Events track emergency actions for public auditing.

Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

TimelockController emergency actions bypass timelock by not enforcing EMERGENCY_DELAY, allowing immediate execution

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

TimelockController emergency actions bypass timelock by not enforcing EMERGENCY_DELAY, allowing immediate execution

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.