Core Contracts

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

Over-Allocation of Funds in Treasury Contract

##Summary

The Treasury contract is vulnerable to over-allocation of funds, allowing an attacker (or even an honest mistake) to allocate more funds than available. This can lead to fund mismanagement, denial of service (DoS), or unintentional fund locking, affecting treasury operations.

##Vulnerability Details

function allocateFunds(address recipient, uint256 amount) external override onlyRole(ALLOCATOR\_ROLE) {
if (recipient == address(0)) revert InvalidRecipient();
if (amount == 0) revert InvalidAmount();
_allocations[msg.sender][recipient] = amount;
emit FundsAllocated(recipient, amount);
}

##Root Cause

The contract does not properly track total allocated funds against the actual treasury balance. This means that it’s possible to allocate more funds than the contract holds, causing payment failures or fund mismanagement.


##Impact

Funds mismanagement: Some addresses may receive more than they should, while others get nothing.
Denial of Service (DoS): If over-allocations occur, legitimate payments might fail.
Potential exploits: A malicious actor could intentionally exploit this to disrupt treasury operations.


##Proof of Concept (PoC)

Here’s a simple test case demonstrating the issue:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Treasury {
mapping(address => uint256) public allocations;
uint256 public totalAllocated;
uint256 public treasuryBalance;
function allocateFunds(address recipient, uint256 amount) public {
require(amount > 0, "Amount must be greater than zero");
// Vulnerability: No check if allocation exceeds available balance
allocations[recipient] += amount;
totalAllocated += amount;
}
function deposit() public payable {
treasuryBalance += msg.value;
}
function withdraw(address recipient) public {
uint256 amount = allocations[recipient];
require(amount > 0, "No funds allocated");
// Possible failure if allocations > treasuryBalance
require(treasuryBalance >= amount, "Insufficient balance");
allocations[recipient] = 0;
treasuryBalance -= amount;
payable(recipient).transfer(amount);
}
}

##Testing the Vulnerability

  1. Deposit 5 ETH into the contract.

  2. Allocate 10 ETH to an address (even though the contract only has 5 ETH).

  3. When the recipient tries to withdraw, the transaction fails due to insufficient funds.

##Security Analysis with Slither & Echidna

Slither Findings: Detects potential reentrancy risks and lack of balance checks.
Echidna Tests: Confirm that allocations can exceed available funds, leading to failures.


##Recommended mitigation(fixes)

Solution 1: Track Total Allocations Against Balance

Modify the allocateFunds() function to ensure total allocations never exceed the treasury balance.

function allocateFunds(address recipient, uint256 amount) public {
require(amount > 0, "Amount must be greater than zero");
// Fix: Ensure total allocated funds do not exceed balance
require(totalAllocated + amount <= treasuryBalance, "Allocation exceeds available funds");
allocations[recipient] += amount;
totalAllocated += amount;
}

##Solution 2: Introduce an Allocation Limit per User

Set a cap on individual allocations to prevent an address from being over-allocated.

uint256 public maxAllocationPerUser = 5 ether;
function allocateFunds(address recipient, uint256 amount) public {
require(amount > 0, "Amount must be greater than zero");
require(amount <= maxAllocationPerUser, "Exceeds max allocation limit");
require(totalAllocated + amount <= treasuryBalance, "Allocation exceeds available funds");
allocations[recipient] += amount;
totalAllocated += amount;
}
Updates

Lead Judging Commences

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

Treasury::allocateFunds doesn't say what token you are actually allocating, doesn't check balances, or existing allocations to other recipients

Support

FAQs

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

Give us feedback!