Status DataClose notification

OpenEden Disclosed Report

Lack of USDC Peg and Price Freshness Validation in OpenEdenVaultV4 Allows Share Inflation and Economic Exploitation During Depeg Events

Company
Created date
Jul 23 2025

Target

https://github.com/OpenEdenHQ/openeden.vault.audit/tree/d18288e944df21729b18d430b2afec2da99b6287

Vulnerability Details

Summary

The OpenEdenVaultV4 contract has completely removed on-chain checks for USDC/USD price peg and price feed freshness that were present in the previous version (V3). In V3, deposit, redemption, and withdrawal queue processing were all gated by a modifier (onlyValidPrice) that required USDC to remain within a configurable depeg threshold and the price feed to be fresh.

In V4, any user can deposit or redeem USDC at a hardcoded $1 rate, even if USDC has lost its peg (e.g., trading at $0.80 on secondary markets), as the contract no longer references any USDC/USD oracle. This exposes the protocol and all vault participants to share inflation and economic loss: attackers can arbitrage by depositing depegged USDC and redeeming for full-value assets, diluting the value of all shares in the vault.


Vulnerability Details

// @audit-issue Lack of USDC peg/freshness guard in deposit/redeem logic
// V3 Example (removed in V4):
modifier onlyValidPrice() {
    (, int256 answer1, , uint256 updateAt, ) = usdcUsdPriceFeed.latestRoundData();
    require(block.timestamp - updateAt <= maxTimeDelay, "stale usdc answer!");
    require(answer1 > 0, "should gt 0");
    uint256 answer = uint256(answer1);
    uint256 depeg = ...;
    require(depeg <= max, "usdc and usd depeg!");
    _;
}

function deposit(...) external onlyValidPrice { ... }
function redeem(...) external onlyValidPrice { ... }
function processWithdrawalQueue(...) external onlyValidPrice { ... }

// V4: All references to onlyValidPrice and usdcUsdPriceFeed removed.
// No on-chain USDC price/freshness checks exist.

Issue Identified

  • V3 required all major user actions to pass USDC/USD price and staleness checks.

  • V4 has no such checks: deposits and redemptions always assume USDC = $1, regardless of actual market price or oracle feed state.

  • Attackers can deposit large amounts of depegged USDC (e.g., trading at $0.80), receive shares valued at $1/USDC, and later redeem for full-value assets once the peg is restored or through alternate redemption mechanisms.


Risk

Likelihood - Medium:

  • USDC depegs have happened historically, and future market shocks remain plausible.
  • There is no need for an attacker to manipulate oracles or perform complex technical attacks—simply acquiring depegged USDC is sufficient.

Impact - High:

  • Share inflation: Attackers extract value from honest vault participants, reducing the share price for everyone else.
  • Large-scale economic loss is possible if depegged USDC is deposited in bulk before manual intervention or pausing by off-chain governance.
  • Permanent protocol loss: Existing users cannot be compensated after dilution occurs.

Tools Used

  • Manual Review

Recommendations

Reintroduce On-Chain USDC Peg and Freshness Checks

Add a modifier (similar to V3's onlyValidPrice) on all deposit, redeem, and withdrawal queue processing entry points, enforcing that:

Example fix:

modifier onlyValidPrice() {
    (, int256 answer1, , uint256 updateAt, ) = usdcUsdPriceFeed.latestRoundData();
    require(block.timestamp - updateAt <= maxTimeDelay, "stale usdc answer!");
    require(answer1 > 0, "bad price");
    uint256 answer = uint256(answer1);
    uint256 numerator = ONE > answer ? ONE - answer : answer - ONE;
    uint256 denominator = (ONE + answer) / 2;
    uint256 depeg = (numerator * ONE) / denominator;
    uint256 max = (maxDepeg * ONE) / BPSUNIT;
    require(depeg <= max, "usdc and usd depeg!");
    _;
}

function deposit(...) external onlyValidPrice { ... }
function redeem(...) external onlyValidPrice { ... }
function processWithdrawalQueue(...) external onlyValidPrice { ... }

This ensures the protocol cannot be economically attacked using depegged USDC or stale price data.


Validation steps

1 . Deploy the OpenEdenVaultV4 contract Deploy OpenEdenVaultV4 with USDC (or mock USDC, 6 decimals) as the underlying token. Make sure the price feed address for USDC/USD is unset or not referenced anywhere in the contract logic.

2 . Simulate a USDC depeg event For testing, simply assume or configure your mock USDC token to have a market price of $0.80 (while the contract will always treat 1 USDC as $1).

3 . Acquire discounted USDC From a different account, acquire 1,000,000 USDC at $0.80 per token (simulate this by minting or transferring tokens).

4 . Approve and deposit depegged USDC Approve the OpenEdenVaultV4 contract to spend your USDC, then call deposit(1_000_000e6, attacker).

5 . Verify shares received Check the attacker’s share balance. It should reflect a value near $1,000,000 (minus any fee), even though attacker only spent $800,000.

6 . Redeem shares when USDC returns to $1 Simulate a return to $1 parity or redemption via redeemIns/redeem. Attacker receives close to $1,000,000 USDC.

7 . Validate economic impact

  • The attacker profits ~$200,000, extracted from vault assets.
  • Other vault participants’ share value is diluted.

Attachments

hidden
CommentsReport History
Comments on this report are hidden
Details
Statedisclosed
Severity
Low
Bounty$12
Visibilitypartially
VulnerabilityOther
Participants (4)
author
manager
triage team