# Transparency Hub v0.1 Threat Model

Status date: 2026-07-14  
Scope: read-only OP Mainnet token, Safe and Uniswap data

## Security invariants

1. **Read only:** no wallet connection, EIP-1193 call, signature, transaction construction or write endpoint. Public APIs allow only `GET`, `HEAD` and `OPTIONS`.
2. **OP Mainnet only:** every request, cache key, export and link binds to `chainId: 10`.
3. **Field-level evidence:** every value carries chain ID, block/time, retrieval time, source, freshness and state.
4. **Failure is not zero:** unknown, stale, conflicting and unavailable data remain `null` with an explicit state. A displayed `0` must be a successfully read zero.
5. **Bounded work:** users cannot choose RPC methods, arbitrary URLs/ABIs, unbounded block ranges or unbounded pagination.
6. **On-chain strings are untrusted:** name, symbol, logo and revert reason are text/data, never HTML or an executable URL.
7. **No v0.1 price or market cap:** a thin-pool spot price is not reliable and `totalSupply` is not circulating supply.

Normalized observation type:

```ts
type Evidence<T> = {
  value: T | null
  state: "verified" | "provisional" | "stale" | "conflict" | "unavailable"
  chainId: 10
  blockNumber?: bigint
  blockHash?: `0x${string}`
  blockTimestamp?: string
  retrievedAt: string
  sources: string[]
  warnings: string[]
}
```

## P0 threats and controls

| ID | Threat | Required control |
|---|---|---|
| TM-01 | Malformed/confusable address, wrong chain, same-symbol impersonation | Accept only ASCII `0x` + 40 hex; validate EIP-55 for mixed case; no ENS; reject zero address; identify assets by chain and full address, never ticker. |
| TM-02 | Wrong-chain, stale or inconsistent RPC | Verify `eth_chainId == 10`; read critical values from two independent providers at the same finalized block/hash; any difference becomes `conflict`. |
| TM-03 | Reorg leaves rolled-back cache | Use `finalized` for fact snapshots; label latest as provisional; key cache by block hash and invalidate descendants when hashes change. OP exposes `safe` and `finalized` block tags.[Optimism transaction status](https://docs.optimism.io/app-developers/guides/transactions/statuses) |
| TM-04 | Safe Transaction Service disagrees with chain | Owners, threshold, nonce, modules, guard, fallback handler, singleton and balances come from direct chain reads. The Safe service supplements history/decoding only; pending signatures are never executed outflows.[Safe Transaction Service](https://docs.safe.global/core-api/api-safe-transaction-service) |
| TM-05 | Hidden Safe module bypasses threshold | Enumerate modules, guard, fallback handler and singleton. Unknown or unexpected modules produce a high-risk alert; `2-of-3` alone is not sufficient evidence. |
| TM-06 | Fake pool, wrong token order or incorrect LP owner | Verify against the fixed official Uniswap factory; check `token0`, `token1`, `fee`; resolve LP NFT ownership with Position Manager `ownerOf(tokenId)`. |
| TM-07 | Thin pool manipulates price/TVL | v0.1 API/UI does not publish price, market cap, FDV or USD TVL. Show raw asset amounts and pool configuration with an explicit thin-market warning. |
| TM-08 | Token metadata XSS or active logo | Render all chain strings as escaped text; no `dangerouslySetInnerHTML`; cap length/control characters; local approved images only, no arbitrary remote SVG. Enforce restrictive CSP. |
| TM-09 | SSRF, DNS rebinding, cloud metadata access | RPC, Safe API and explorer origins are server allowlisted. Manifest URLs are not fetched. No custom RPC, logo URL, webhook or redirect-following proxy. |
| TM-10 | Huge logs or hostile ABI response causes DoS | Fixed address/topic background indexing, checkpoints and bounded chunks; cap pages, response bytes, ABI return length, owner/module count, time and concurrency. |
| TM-11 | Cache poisoning or cross-address/cross-chain data | Key includes schema version, chain ID, normalized address, resource, block hash and source set. Ignore client-supplied host/chain/source headers; cache only schema-valid results. |
| TM-12 | Social engineering or future wallet-feature regression | Every page states read-only/no wallet/no signature/no seed phrase. No Connect, Claim, Approve, Sign, Buy or QR action. External links are approved and use `noopener noreferrer` plus no referrer. |

Recommended CSP baseline:

```text
default-src 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'
```

## P1 privacy and operations

- No session replay, ads, remote fonts or query-address analytics.
- Do not retain an IP-to-address-query mapping; remove query strings from logs and set a short retention period.
- Disable camera, microphone and geolocation via `Permissions-Policy`; enable HSTS, same-origin CORS and `X-Content-Type-Options: nosniff`.
- Only allowlisted assets enter Treasury totals; spam airdrops and duplicate symbols are listed separately as unverified.
- Use `bigint` or a decimal library, never JavaScript `Number`, for token amounts.
- Pin dependencies, generate an SBOM and scan secrets/dependencies; permit disabling one source/field while publishing an incident notice.

## Minimum acceptance tests

1. A provider returning chain ID 1 is quarantined before any value renders.
2. Two providers disagreeing at one finalized block produce `conflict`, not an averaged or selected value.
3. Stale Safe owners, `synced=false` or a pending Safe transaction cannot override chain state.
4. A Safe fixture with an unexpected module triggers a high-risk warning.
5. A changed block hash invalidates affected snapshots, events and CDN cache.
6. HTML/script payloads, Unicode spoof symbols and malicious SVG never execute or change DOM structure.
7. Loopback, link-local, IPv6 loopback, private redirect and DNS-rebinding destinations receive no outbound request.
8. Huge log ranges, long strings and oversized address batches are rejected before RPC access.
9. Timeout, 429/500, malformed JSON and oversized ABI returns display unavailable/stale, never `0`.
10. Host header, address case, query order and client-supplied chain headers cannot cross-pollute cache entries.
11. A 1,000x spot manipulation or null price source still yields no market-cap/FDV field.
12. A recording `window.ethereum` receives zero calls across every route.
13. The build contains no WalletConnect relay, `eth_requestAccounts`, `eth_sendTransaction`, `personal_sign` or `eth_signTypedData*`.
14. Public `POST/PUT/PATCH/DELETE` return `405`; non-allowlisted RPC methods are rejected server-side.
15. External links send no address-bearing referrer and do not silently jump to interactive Safe/DEX pages.
16. The Montrevane 20-field fixture agrees across two RPCs at one recorded finalized block or carries an explained evidence state.

## Residual risk

Two RPC brands can share one upstream; a malicious browser extension can alter the rendered page; very thin liquidity remains manipulable; and a third-party indexer can lag even when reporting healthy. A read-only label does not remove these risks, so source and state remain visible for every observation.

