Core Contracts

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

Missing Input Validations in ZENO Contract Constructor: Risk of Invalid Initialization and Auction Misbehavior

Summary

The ZENO contract is designed to manage ZENO token issuance and functionality, relying on proper initialization of critical parameters such as the USDC token address and the token’s maturity date. However, the constructor of the ZENO contract lacks essential input validations:

  • It does not check that the _usdc address is non-zero.

  • It does not validate that the _maturityDate is set to a future timestamp with an adequate buffer.

Without these validations, the contract can be deployed with invalid parameters (e.g., a zero address for USDC or a past maturity date), which can cause malfunctioning during auction operations or token interactions.

The attached test suite demonstrates that the contract accepts invalid inputs—resulting in zero values for USDC and maturity date—thereby confirming the vulnerability. This misinitialization may lead to unpredictable behavior in auctions and token transfers, ultimately undermining protocol stability and stakeholder confidence.

Vulnerability Details

Issue Overview

The constructor of the ZENO contract is defined as follows:

constructor(
address _usdc,
uint256 _maturityDate,
string memory _name,
string memory _symbol,
address _initialOwner
)
Ownable(_initialOwner)
ERC20(_name, _symbol)
{
// @info: missing address check for usdc address
// @info: missing date checks i.e., maturity date must be a future date with some date threshold
USDC = IERC20(_usdc);
MATURITY_DATE = _maturityDate;
}

Identified Omissions:

  • Zero Address Check:
    The constructor fails to validate that _usdc and _initialOwner are non-zero addresses. An invalid (zero) USDC address means that any interactions expecting a proper USDC token will fail.

  • Maturity Date Validation:
    There is no check ensuring that _maturityDate is in the future (with an acceptable minimum delay). A maturity date set to the current timestamp or a past timestamp may lead to immediate or unexpected triggering of maturity-dependent logic.

  • Time and Value Consistency:
    The absence of validations for time dimensions (e.g., ensuring the auction start and end times are set correctly) can lead to auctions with invalid timing, further compounding potential operational issues.

How It Arises

Because the constructor does not enforce these checks, a deployer could inadvertently (or maliciously) initialize the contract with:

  • A zero address for _usdc, causing any USDC-based operations to malfunction.

  • A maturity date that is either in the past or too soon, resulting in immediate maturity and potentially breaking time-dependent functions.

The provided test suite explicitly creates a ZENO instance with zero values for these parameters, confirming that the constructor does not revert or prevent invalid initialization.

Proof of Concept

Test Suite Walkthrough

The following test suite demonstrates the issue:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {Test, console} from "forge-std/Test.sol";
import {ZENO} from "../src/zeno/ZENO.sol";
import {Auction} from "../src/zeno/Auction.sol";
import {USDCMock} from "./mocks/USDCMock.m.sol";
import {BusinessMock} from "./mocks/BusinessMock.m.sol";
import {IAuction} from "../src/interfaces/zeno/IAuction.sol";
contract ZenoAuction is Test {
ZENO zeno;
Auction auction;
USDCMock usdcMock;
BusinessMock businessMock;
address USDC_MOCK_OWNER = makeAddr("USDC_MOCK_OWNER");
address BUSINESS_MOCK_OWNER = makeAddr("USDC_MOCK_OWNER");
address ZENO_OWNER = makeAddr("ZENO_OWNER");
address AUCTION_OWNER = makeAddr("AUCTION_OWNER");
uint256 startTime = block.timestamp;
uint256 endTime = block.timestamp + 30 days;
uint256 startingPrice = 10e18;
uint256 reservePrice = 5e18;
uint256 totalAllocated = 20e18;
uint256 zenoMaturityDate = block.timestamp + 10 days;
string zenoName = "ZENO_V1";
string zenoSymbol = "ZENOV1";
function setUp() public {
// ignore this setUp function
vm.startPrank(USDC_MOCK_OWNER);
usdcMock = new USDCMock();
vm.stopPrank();
vm.startPrank(BUSINESS_MOCK_OWNER);
businessMock = new BusinessMock();
vm.stopPrank();
vm.startPrank(ZENO_OWNER);
zeno = new ZENO(address(usdcMock), zenoMaturityDate, zenoName, zenoSymbol, ZENO_OWNER);
vm.stopPrank();
vm.startPrank(AUCTION_OWNER);
auction = new Auction(
address(zeno),
address(usdcMock),
address(businessMock),
startTime,
endTime,
startingPrice,
reservePrice,
totalAllocated,
AUCTION_OWNER
);
vm.stopPrank();
}
function testInvalidUSDCAddressAndMaturityDate() public {
vm.startPrank(ZENO_OWNER);
// Deploy ZENO with invalid parameters: zero USDC address and zero maturity date.
ZENO newZeno = new ZENO(address(0), 0, zenoName, zenoSymbol, ZENO_OWNER);
vm.stopPrank();
assertEq(address(newZeno.USDC()), address(0));
assertEq(newZeno.MATURITY_DATE(), 0);
}
}

Observations

  • Test Outcome:
    The test successfully deploys a ZENO contract with a zero address for USDC and a maturity date of 0, indicating that the constructor lacks proper validations.

  • Implication:
    Such an initialization would lead to operational failures when the contract attempts to interact with USDC or enforce maturity-based logic, potentially breaking auction functions and destabilizing the protocol.

Impact

  • Operational Failure:
    An invalid USDC address prevents the ZENO contract from interacting with the intended stablecoin, leading to failed transfers and broken functionality.

  • Time-Dependent Logic Breakdown:
    An improperly set maturity date (e.g., in the past or zero) can trigger premature maturity events or disable time-based features, undermining the economic design.

  • Economic Exploitation:
    Invalid initialization parameters can be exploited to disrupt auctions or token sales, causing financial losses or unfair advantages.

  • Loss of Stakeholder Trust:
    Deployments with invalid parameters compromise the protocol’s reliability, reducing user confidence and participation.

Tools Used

  • Manual Review

  • Foundry

Recommendations

To secure the ZENO contract, update the constructor with comprehensive input validations:

  1. Non-Zero Address Checks:
    Ensure that _usdc and _initialOwner are not the zero address.

  2. Maturity Date Validation:
    Verify that _maturityDate is set to a future timestamp with an appropriate minimum delay (e.g., at least 1 day in the future).

  3. Optional Additional Checks:
    Consider validating other parameters (if applicable) such as ensuring non-zero values for _name, _symbol, and any critical numerical parameters.

Proposed Diff for ZENO Constructor

constructor(
- address _usdc,
- uint256 _maturityDate,
- string memory _name,
- string memory _symbol,
- address _initialOwner
-)
- Ownable(_initialOwner)
- ERC20(_name, _symbol)
-{
- // @info: missing address check for usdc address
- // @info: missing date checks i.e., maturity date must be a future date with some date threshold
- USDC = IERC20(_usdc);
- MATURITY_DATE = _maturityDate;
-}
+ address _usdc,
+ uint256 _maturityDate,
+ string memory _name,
+ string memory _symbol,
+ address _initialOwner
+)
+ Ownable(_initialOwner)
+ ERC20(_name, _symbol)
+{
+ // Validate that USDC address is not the zero address.
+ if (_usdc == address(0)) revert InvalidAddress();
+
+ // Validate that the maturity date is in the future (e.g., at least 1 day from now).
+ if (_maturityDate <= block.timestamp + 1 days) revert InvalidMaturityDate();
+
+ // Validate that the initial owner is not the zero address.
+ if (_initialOwner == address(0)) revert InvalidAddress();
+
+ USDC = IERC20(_usdc);
+ MATURITY_DATE = _maturityDate;
+}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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

Give us feedback!