Skip to content

Latest commit

 

History

History
87 lines (62 loc) · 3.45 KB

026.md

File metadata and controls

87 lines (62 loc) · 3.45 KB

Old Boysenberry Reindeer

High

Incorrect time validation in currentValue function will allow stale prices for users.

Summary

A logical error in the currentValue function of the PythOracle contract allows stale prices to be considered valid while rejecting newer prices. This issue occurs because the condition incorrectly checks whether the price is too “new” rather than ensuring it is not stale. As a result, users may rely on outdated price data, leading to inaccurate calculations in the protocol.

Root Cause

In PythOracle.sol:29 https://github.com/sherlock-audit/2024-11-oku/blob/main/oku-custom-order-types/contracts/oracle/External/PythOracle.sol#L29

This condition allows prices that are older than noOlderThan seconds but rejects newer prices. The correct validation should ensure the price is at least as recent as block.timestamp - noOlderThan, rejecting any prices that are too old.

Internal pre-conditions

  1. price.publishTime is set to a timestamp older than block.timestamp - noOlderThan.
  2. noOlderThan is configured (e.g., 3 days = 259200 seconds).
  3. The function is invoked to fetch the current price value.

External pre-conditions

  1. The oracle provides a price with a publishTime older than the configured noOlderThan period.
  2. The protocol relies on the oracle’s currentValue for subsequent calculations, assuming the price is valid.

Attack Path

  1. Step 1: A price with a stale publishTime is returned by the oracle. • Example: publishTime = 15th January, block.timestamp = 20th January, noOlderThan = 3 days. • Calculation: 15 < 20 - 3 = 17 → Passes as valid, though it is stale.
  2. Step 2: A price with a newer publishTime fails validation. • Example: publishTime = 15th January, block.timestamp = 17th January, noOlderThan = 3 days. • Calculation: 15 < 17 - 3 = 14 → Fails as invalid, though it is recent.
  3. Step 3: Inaccurate price data is used in calculations, leading to potential financial losses or incorrect protocol behavior.

Impact

Stale prices will be accepted, while recent, valid prices may be rejected. This can lead to: • Inaccurate financial calculations. • Increased risk of economic attacks based on outdated data.

PoC

    function testOracle() external {
        uint256 publishTime = 15 days;
        uint256 timestamp_1 = 20 days; // should be invalide
        uint256 timestamp_2 = 17 days; // should be valide
        uint256 noOlderThan = 3 days;

        if (publishTime < timestamp_1 - noOlderThan) {
            console.log("Stale price is valid in 1st case");
        } else {
            console.log("New price is invalid in 1st case");
        }

        if (publishTime < timestamp_2 - noOlderThan) {
            console.log("Stale price is valid in 1st case");
        } else {
            console.log("New price is invalid in 1st case");
        }

        if (publishTime + noOlderThan >= timestamp_1) {
            console.log("New price is valid in 2nd case" );
        } else {
            console.log("Stale price is invalid in 2nd case");
        }
        
        if (publishTime + noOlderThan >= timestamp_2) {
            console.log("New price is valid in 2nd case" );
        } else {
            console.log("Stale price is invalid in 2nd case" );
        }

    }

Mitigation

Replace the incorrect validation with the correct condition to ensure only recent prices are accepted:

require( price.publishTime + noOlderThan >= block.timestamp, "Stale Price" );