Core Contracts

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

Non-Payable `Governance.execute` Function Prevents Proposals with Value Transfers

Summary:

The Governance::execute function is declared as a non-payable. This prevents the execution of any governance proposal that includes value transfers (i.e., where the values array in the proposal contains elements greater than 0). Because msg.value cannot be sent to a non-payable function, any attempt to execute such a proposal will revert with an "out of funds" error.

Vulnerability Details:

The Governance::execute function is responsible for executing a proposal after it has been queued in the TimelockController. Within execute, the contract calls the target contracts specified in the proposal, potentially transferring value using the values array and the call function. However, because the execute function itself is not payable, it cannot receive any msg.value. Consequently, when the execute function attempts to call the target contracts with value transfers (e.g., targets[i].call{value: values[i]}(calldatas[i])), the calls will fail because the Governance contract has no funds to send. The transaction will revert with an "out of funds" error, effectively blocking the execution of any proposal involving value transfers.

// In Governance.sol
function execute(uint256 proposalId) external override nonReentrant { // <--- Not payable!
ProposalCore storage proposal = _proposals[proposalId];
// ... other checks ...
}

The crucial part is the targets[i].call{value: values[i]}(calldatas[i]) line in TimelockController.executeBatch fuction. If values[i] is greater than 0, this call will require the Governance contract to have some Ether to send. Since execute is not payable, the contract will not have any Ether, leading to the "out of funds" revert.

Impact:

  • Proposal Execution Failure: Any proposal that requires transferring value to target contracts will fail to execute. This severely limits the types of actions that can be implemented through governance proposals.

  • Governance Functionality Breakdown: A core feature of a governance system is the ability to manage and modify the protocol, which often includes transferring assets. This vulnerability cripples this functionality.

PoC (Proof of Concept):

  1. Create Proposal (with Value Transfer): Create a governance proposal that includes at least one target contract address and a corresponding value in the values array greater than 0. This proposal should be designed to transfer some amount of tokens or Ether.

  2. Queue Proposal: Have the proposal pass the quorum requirements and be queued in the TimelockController.

  3. Attempt Execution: Call the Governance::execute function.

  4. Observe Revert: The transaction will revert with an "out of funds" error because the execute function is not payable and cannot forward the required msg.value.

Recommended Mitigation:

Make the Governance::execute function payable. This will allow the contract to receive and forward Ether or tokens to the target contracts during proposal execution.

// In Governance.sol (Fixed Code)
- function execute(uint256 proposalId) external override nonReentrant {
+ function execute(uint256 proposalId) external override payable nonReentrant {
ProposalCore storage proposal = _proposals[proposalId];
// ... other checks ...
// ...
}
Updates

Lead Judging Commences

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

Governance.execute lacks payable modifier and ETH forwarding mechanism, preventing proposals with ETH transfers from being executed through TimelockController

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

Governance.execute lacks payable modifier and ETH forwarding mechanism, preventing proposals with ETH transfers from being executed through TimelockController

Support

FAQs

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

Give us feedback!