# A malicious signed price can be injected in assets.price_tick()

Missing existence check in _validate_oracle_signature lets any unregistered key sign arbitrary asset prices, bypassing governance-approved oracle set.

- Payout: Contest reward
- Severity: high
- Program: Starknet Perpetual
- Credited: alexxander
- Disclosed: 2025-06-18
- Write-up quality: 7/10
- Original: https://code4rena.com/reports/2025-03-starknet-perpetual#h-01
- Library page: https://bugbountylibrary.com/r/c4%3A2025-03-starknet-perpetual%3AH-01
- Tags: domain:web3 impact:funds-loss impact:integrity kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:auth-bypass vuln:oracle-manipulation vuln:signature-replay

**Target:** assets.price_tick / _validate_oracle_signature in Starknet Perpetual Cairo contracts
**Root cause:** asset_oracle.entry(asset_id).read(signer_public_key) returns zero for unknown keys instead of panicking, so an attacker signs pedersen(0, price||timestamp) with their own key and passes validation.
**Steps:**
1. Call assets.price_tick with signed_prices containing a SignedPrice whose signer_public_key is not registered via add_oracle_to_asset.
2. Compute msg_hash = pedersen(0, oracle_price * 2^32 + timestamp) since packed_asset_oracle reads as zero.
3. Sign msg_hash with the attacker's key pair and submit; validate_stark_signature passes.
4. Observe PriceTick event with attacker-chosen price (e.g. 100_000 vs 100).
**How found:** Code review of _validate_oracle_signature noticed storage read of unknown key returns zero rather than reverting, unlike add_oracle_to_asset which asserts is_zero.
**Exploitation:** Attacker registers no oracle; crafts a SignedPrice with arbitrary signer key, signs pedersen(0, chosen_price||timestamp), and submits to price_tick, setting any asset price to any value.
**Escalation:** Arbitrary price feeds enable manipulation of synthetic asset valuations, liquidations, and PnL accounting.
**Insight:** In Cairo/Starknet storage maps, reading an unset key returns zero silently; any signature-validation path that reads a registry entry must explicitly assert non-zero before trusting the packed value.
