> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cryptocheckout.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Threat model

> What the system defends against, what it does not, and the hardening that shipped after each audit.

Full detail: `docs/SECURITY_THREAT_MODEL.md` and `docs/audits/2026-07-28-production-readiness-audit.md`.

## Trust boundaries

| Component               | Trusted for                        | Not trusted for                                                               |
| ----------------------- | ---------------------------------- | ----------------------------------------------------------------------------- |
| Chain                   | Everything about money and routing | Nothing                                                                       |
| Postgres                | Display, analytics, operations     | **The fund path**                                                             |
| Edge function responses | Convenience hints                  | Anything the client can verify itself                                         |
| Keeper                  | Liveness                           | Directing funds — it re-resolves on-chain and gates on the re-derived address |
| Merchant's own site     | The settlement anchor pin          | —                                                                             |

## Attacks defended

<AccordionGroup>
  <Accordion title="Database compromise redirecting payments">
    Blocked by client-side on-chain re-derivation. A self-consistent tamper fails because verification anchors to the chain. See [DB-display-only trust](/trust/db-display-only).
  </Accordion>

  <Accordion title="Recipient changed between quote and signature">
    The widget re-reads `effectiveRecipient` immediately before signing. Mismatch produces a `recipient_changed` state with no signature sent.
  </Accordion>

  <Accordion title="Merchant not attested">
    `create-payment-intent` performs an `eth_call` against `MerchantRegistry.effectiveRecipient` on the payment chain. No attestation returns HTTP 422 with a stable error code, so the customer never signs a transaction that would revert.
  </Accordion>

  <Accordion title="SSRF via webhook URL">
    `_shared/url-allowlist.ts` is the single source of truth. `merchants.webhook_url` carries a CHECK constraint via `is_safe_webhook_url(text)`, and the delivery function re-validates at fetch time. Blocks loopback, RFC 1918, 169.254 cloud metadata, CGNAT, IPv6 ULA and link-local, non-HTTP schemes, and non-canonical ports.
  </Accordion>

  <Accordion title="Loopback SIWE origin minting production sessions">
    `siwe-verify` and `siwe-whoami` once shipped `localhost:5173,localhost:8080` in their default allowlists and production never overrode them — a page on those ports could mint a real 24-hour production session, reproduced live. Loopback is now stripped unless an explicit flag is set **and** the Supabase URL is genuinely localhost; setting the flag on a hosted URL throws at boot. CORS refuses to credential-reflect loopback as a second line of defence.
  </Accordion>

  <Accordion title="Nonce table exposure">
    `siwe_nonces` has explicit `service_role` ALL ALLOW plus anon and authenticated ALL DENY policies. The prior state was deny-by-default with no policies, which worked but left the intent undocumented — a future GRANT could have opened a hole silently.
  </Accordion>

  <Accordion title="Sanctioned recipient locking a pool forever">
    Recipient and partner payout addresses are screened **before** being baked into a pool's immutable init code. A sanctioned address in an immutable pool would permanently lock funds. The partner is screened here regardless of sign-in history, because a referrer auto-created from a code may never have signed in.
  </Accordion>
</AccordionGroup>

## Known-unfixed and accepted

<Warning>
  **`paymentId` replay is keyed on `paymentId` alone**, not `(merchant, paymentId)`. With 128-bit random identifiers, cross-merchant griefing is infeasible at roughly 2⁻⁶⁴. Documented as deferred; a future redeploy could move to composite keying.
</Warning>

Open items from the 2026-07-28 audit, deliberately left:

* `RouterFee` `V3_SWAP_EXACT_OUT = 0x09` mis-encoding (that is V2's opcode). Needs a redeploy, Phase 2 only.
* Partner earnings always display \$0.00, and partner-visible merchants RLS is incomplete.
* Webhook `'none'` secret option, and a test-versus-live signature mismatch.
* TRON keeper drops expired intents.
* TRON has no on-chain recipient anchor, so the trust guarantee does not extend there.

## Economic attacks

**Self-dealing at the floor.** A merchant mints invoices at the minimum and pays them to themselves, recovering 99% while the platform eats the sponsored gas. Leverage was measured at 6.4:1 on Ethereum — roughly $2,100 of attacker spend to burn $13,700 of keeper float across 100,000 invoices.

Largely defused once the merchant bears their own invoices' gas: the attack costs the attacker more than it costs the platform.

**Cheap account creation.** 10,000 fake merchant accounts cost nothing to create and could trigger keeper-funded pool deploys — $99 on Base, **$288,200 on TRON\*\*. The cost is not the point on EVM; the *unauthenticated ability to make the platform spend* is. Closed by making pool deployment merchant-paid and a prerequisite for SDK access.

**Griefing the reimbursement cap.** `distribute()` is permissionless, so anyone can call it with a cost parameter at the ceiling. They gain nothing but can shave a merchant's payout up to the cap. Bounded nuisance rather than theft — provided the cap is `min(bps, absolute)` and tight. A bps-only cap on a large order authorises a very large claim.

**Address pre-derivation.** For per-customer forwarders, the customer identifier must not be guessable, or a third party could pre-derive addresses and grief a merchant.

## Fail-open decisions

Both sanctions layers fail **open** — an RPC outage returns unknown and allows the payment through. This is deliberate: a screening outage should not halt legitimate commerce, and the platform-level sign-in gate remains the enforcement point for merchants.

Conversely, the economics floor must fail **closed** to a recalibrated conservative table, never to zero. An economics gate that fails open quotes a guaranteed loss.
