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