Skip to content
Corngate

Documentation centre

Threat model

Assets, adversaries and mitigations across web, database, storage and chain.

Rendered from docs/THREAT_MODEL.md in the repository — the file is the source of truth. All documents

Scope: public website + seeded registry (current), with forward posture for Phases 3–6 (auth, uploads, certificates, payments). Method: assets → adversaries → attacks → mitigations. Revisit at every phase gate.

Assets worth protecting

  1. Registry integrity — statuses, claims, history (the product is trust)
  2. Precise geometry & identity documents — safety + data protection
  3. Issuer keys — Amoy now, mainnet someday; also Supabase service role
  4. Funds & payment data — Phase 6
  5. Reputation for honesty — simulated vs real labelling

Adversaries

Opportunistic scrapers/bots · land-dispute counterparties seeking data or manipulation · fraudulent registrants (fake/duplicate assets) · insider error (most likely!) · key thieves · demo-day failure modes (offline, expired tokens).

Attacks and mitigations

A. Public web (current build)

ThreatMitigation
Scraping precise farm locationsOnly generalised geometry exists client-side (fixtures contain no precise data); Phase 3 keeps precise columns behind no-anon RLS
Content injection via search paramsq/type/status validated against allowlists; React escapes output; no dangerouslySetInnerHTML
Fake-record confusionRegistry refs are unique + human-quotable; superseded/revoked records stay visible with reasons
Demo failure (no network/keys)Fixture-first data layer; schematic SVG map; system fonts; zero runtime secrets

B. Registration & verification (Phase 3 posture)

ThreatMitigation
Duplicate/overlapping claimsGeometry overlap + proximity screening before verifier review; disputes as first-class workflow
Fraudulent evidencesha256 at upload; verifier review; field inspection tier for higher-value claims; revocation with public reasons
Privilege escalationRoles in user_roles granted by admin only; RLS has_role() checks; audit log on grants
IDOR on evidence filesPrivate bucket; server-issued short-lived signed URLs after grant check; no direct storage paths in client
Mass-assignment / injectionZod validation on every server action; parameterised queries via Supabase client

C. Chain & keys (Phase 5 posture)

ThreatMitigation
Issuer key theftKey separation: deployer ≠ issuer ≠ admin; keys in Vercel/GH encrypted secrets, never in repo; Pausable contract; revocation path
Wrong data pinned foreverPre-pin review against DATA_CLASSIFICATION.md; metadata contains public-class fields only; versioned tokenURI
Token misinterpreted as titleTransfers disabled; contract emits registry ref; UI copy; docs
Testnet/mainnet confusionAmoy-only check constraint; distinct explorer links; mainnet checklist gate

D. Payments (Phase 6 posture)

Mock mode default; provider adapter isolates PCI surface to the provider's hosted flow; sponsorship requires recorded disclosure acceptance; refund path documented before live mode; no card data ever touches Corngate servers.

Key management (summary)

  • Never in repo. .env git-ignored; .env.example documents names only.
  • Supabase service-role key: server-only, never NEXT_PUBLIC_*.
  • Amoy deployer/issuer keys: generated fresh for the pilot, funded minimally, stored in platform secret managers; rotation documented in DEPLOYMENT runbook (Phase 10).
  • Mainnet keys: do not exist in v0.1 (see REGULATORY_BOUNDARIES §5).

Incident posture

Audit log append-only; single admin contact route (/contact → founder) for disputes/takedowns; incident notes belong in STATUS.md changelog until a formal register exists (Phase 9).