# Oracles are vulnerable to cross-chain replay attacks

GMX Oracle hard-codes a SALT from block.chainid at construction, letting keeper price signatures be replayed across a chain fork to set invalid prices.

- Payout: Contest reward
- Severity: medium
- Program: Gmx
- Credited: IllIllI
- Disclosed: 2022-09-22
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-02-gmx-judging/issues/152
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-02-gmx%3AM-24
- Tags: domain:web3 impact:funds-loss impact:integrity kind:contest platform:sherlock sev:medium tech:evm tech:solidity technique:source-review vuln:signature-replay

**Target:** Oracle.sol price signing / OracleUtils signature verification
**Root cause:** SALT is computed once in the constructor as keccak256(abi.encode(block.chainid, "xget-oracle-v1")) and signatures include SALT but not block.chainid separately, so the chain identity is frozen at deploy time and identical across forks.
**Steps:**
1. Read Oracle.constructor: `SALT = keccak256(abi.encode(block.chainid, "xget-oracle-v1"))`
2. Observe OracleUtils signature verification uses SALT without re-including current block.chainid
3. On a hard fork, both chains share the same SALT and keeper keys
4. Replay a keeper-signed price payload from the original chain onto the fork
5. Fork chain accepts stale/incorrect prices, enabling invalid executions or liquidations
**How found:** Code review of the Oracle constructor and signature verification: noticed SALT bakes in block.chainid only at construction and is not re-checked per signature, implying fork replay.
**Exploitation:** A keeper (not fully trusted per README) on the forked chain submits oracle price signatures produced on the original chain; since SALT matches, the fork contract accepts prices that may be wrong for that chain (e.g. USDC worth zero pre-Circle support), yielding invalid execution prices and liquidations.
**Insight:** When a domain separator/SALT is cached in a constructor, check whether chainid is re-read at verification time; cached chainid breaks EIP-712-style replay protection across forks.
