Summary
submit_data() in contracts/oracle-verifier/src/lib.rs (line 130) accepts a caller-supplied timestamp: u64 with no validation against the ledger clock. An oracle can submit a data point with timestamp = u64::MAX or any future value, making their submission appear more recent than all others when get_data() selects the latest by timestamp.
Code
pub fn submit_data(
env: Env,
oracle: Address,
data_type: Symbol,
key: Symbol,
value: i128,
confidence: u32,
timestamp: u64, // ← no validation against env.ledger().timestamp()
) {
oracle.require_auth();
if confidence > 100 { panic_with_error!(&env, Error::InvalidConfidence); }
// ... timestamp is stored as-is
let new_point = OracleDataPoint { oracle: oracle.clone(), value, confidence, timestamp };
get_data() selects the most recently timestamped submission — not the most recently submitted ledger:
if p.timestamp > latest.timestamp { latest = p; }
Attack Scenarios
- Stale-data injection: A deregistered or compromised oracle submits data with a future timestamp. Its value dominates the median, overriding fresher submissions from legitimate oracles.
- Freshness bypass:
verify_trigger_fresh rejects data older than max_age_seconds. An oracle submits with timestamp = now + max_age_seconds + 1 to ensure their stale data is always accepted as fresh.
Fix
Reject submissions where timestamp is more than a small grace window into the future:
let now = env.ledger().timestamp();
if timestamp > now + 300 { // 5-minute grace window
panic_with_error!(&env, Error::InvalidTimestamp);
}
Severity: High
Summary
submit_data()incontracts/oracle-verifier/src/lib.rs(line 130) accepts a caller-suppliedtimestamp: u64with no validation against the ledger clock. An oracle can submit a data point withtimestamp = u64::MAXor any future value, making their submission appear more recent than all others whenget_data()selects the latest by timestamp.Code
get_data()selects the most recently timestamped submission — not the most recently submitted ledger:Attack Scenarios
verify_trigger_freshrejects data older thanmax_age_seconds. An oracle submits withtimestamp = now + max_age_seconds + 1to ensure their stale data is always accepted as fresh.Fix
Reject submissions where
timestampis more than a small grace window into the future:Severity: High