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

# Security

> Trust assumptions first, then the threat model summary, key custody, review findings and the mainnet gate checklist.

The canonical threat model is [`docs/THREAT-MODEL.md`](https://github.com/Udoka-AM/sealForge/blob/main/docs/THREAT-MODEL.md): assets, adversaries, what is and isn't protected, how, and the code or test that enforces each row. The security review with findings is [`docs/SECURITY-REVIEW.md`](https://github.com/Udoka-AM/sealForge/blob/main/docs/SECURITY-REVIEW.md). This page summarises both and holds the mainnet gate checklist.

## Trust assumptions

Stated first, because every guarantee depends on them. Full text: [THREAT-MODEL.md §Trust assumptions](https://github.com/Udoka-AM/sealForge/blob/main/docs/THREAT-MODEL.md#trust-assumptions).

1. **Deposit mode: the coordinator sees bid amounts live.** It holds the UFVK to scan. Trustees hold no viewing key. Use sealed-reveal mode to hide prices from the coordinator until the reveal window. Deposit sizes stay visible.
2. **The coordinator samples `nk` and `rivk` and holds the UFVK** (encrypted with `SF_DATA_KEY`). That is viewing power, not spending power.
   * A database dump plus `SF_DATA_KEY` gives an attacker every escrow's notes in both directions, so sealing breaks for deposit-mode amounts, and refund addresses leak. Funds don't move.
   * Two trustee shares give spend signatures. Building a spend also needs the escrow FVK, which lives only in the coordinator database under `SF_DATA_KEY`.
3. **Trustees sign blind.** They receive the sighash and α, not the PCZT, so they can't check what a refund or payout pays. A malicious or compromised coordinator plus two trustees signing as instructed can redirect escrowed funds. This is the most important gap before mainnet.
4. **Liveness.** Refunds need the organiser to publish, the coordinator to build, and two trustees to sign. Any of them can delay. Funds stay in the escrow meanwhile.
5. **The published UIVK is permanent.** After publish, every deposit's amount and memo (code, commitment, refund address) and every reveal (price, salt) is readable by anyone, forever. Senders are not, and outgoing refunds are not.

## Threat model summary

| Adversary | Outcome |
| - | - |
| Chain observer during the auction | Sees nothing about bids |
| Chain observer after publish | Sees amounts and refund addresses, not senders |
| Organiser or coordinator publishing a false result | Detected by the chain audit |
| Hiding a bid from the published list | Detected within the audited block range |
| Coordinator, deposit mode | Sees amounts |
| Coordinator, sealed-reveal mode | Sees deposits, not prices, until the reveal window |
| Coordinator building a malicious spend | **Not protected** (assumption 3) |
| One rogue trustee | Can't sign |
| Coordinator during the DKG | Relays only. Signed and sealed packages, agreement check, fingerprint |
| Replay or forgery of API calls | `SF-Sig`, ±60 s, nonce store |
| Refund amount matching at the exit | Mitigated ([2.7](https://sealforge.mintlify.site/protocol/refunds.md)) |
| Source-chain observer (ShieldRamp) | Not built |

Each row's mechanism and enforcing code: [THREAT-MODEL.md](https://github.com/Udoka-AM/sealForge/blob/main/docs/THREAT-MODEL.md#adversaries-and-protections).

## Key custody

The custody table (where each key lives and what stealing it gives) is in [SECURITY-REVIEW.md §Key handling](https://github.com/Udoka-AM/sealForge/blob/main/docs/SECURITY-REVIEW.md#key-handling-what-an-attacker-gets). One addition from this review: the escrow FVK components `nk` and `rivk` are generated by the coordinator ([3 Escrow key construction](https://sealforge.mintlify.site/zcash-integration.md#escrow-key-construction)), and the PCZTs the coordinator builds are not shown to trustees.

## Findings

From the review on 2026-10-15 ([SECURITY-REVIEW.md](https://github.com/Udoka-AM/sealForge/blob/main/docs/SECURITY-REVIEW.md#findings-fixed-in-this-review)):

| # | Severity | Finding | Status |
| - | - | - | - |
| F1 | Medium | rustls advisories | Fixed (updated) |
| F2 | High | Unchecked refund address could block every refund batch, and a Sapling-only address crossed pools | Fixed, test `records_payments_with_memo_level_checks` |
| F3 | High (availability) | Concurrent DKG completion deadlocked | Fixed, row locks. `dkg_e2e` |
| F4 | Medium (availability) | An offline chosen signer stranded a batch | Fixed, 30-minute reset |
| F5 | Medium | No CSP or framing protection | Fixed, production CSP and `frame-ancestors 'none'` |
| F6 | Low | Escrow wallet files had default permissions | Fixed, 0700 |
| F7 | Low | `SF_DATA_KEY` visible in `ps` during the restore drill | Fixed, SQL over stdin |
| F8 | Medium | Late payments weren't refunded | Fixed, `late` status and late-refund planner |

Found while writing these docs (2026-11-13), not yet fixed:

| # | Severity | Finding | Where |
| - | - | - | - |
| D1 | **High** | Trustees sign a sighash without the PCZT, so they can't verify outputs (trust assumption 3) | `crates/sealforge-cli/src/trustee.rs` `sign_step`; `crates/sealforge-signer-wasm`; `BatchView` in `crates/sealforge-api/src/types.rs` |
| D2 | Medium | Three of four committed WASM modules were built from a dirty tree (`source_dirty: true`), so they can't be reproduced from the recorded commit | `apps/web/public/{auditor,signer,wallet}/BUILD.json` |
| D3 | Low | Batch status `failed` is never set, so a transaction that expires unmined isn't detected automatically | `crates/sealforge-coordinator/src/scanner.rs` |
| D4 | Low | Documented retention (UFVK and refund addresses deleted 30 days after settlement) is not implemented | [4 Architecture §Data model](https://sealforge.mintlify.site/architecture.md#data-model) |

## Open items from the review

| Item | Status |
| - | - |
| Rate limiting on public endpoints | Open. Mainnet gate |
| Strict nonce-based CSP (drop `'unsafe-inline'`) | Open. Decision needed before mainnet |
| Coordinator sees deposit-mode bids before close | By design. Sealed-reveal mode is the mitigation |
| Browser trustee holds the key share in JS memory while the page is open | Documented. The CLI is recommended for large auctions ([7 Guides](https://sealforge.mintlify.site/guides.md#trustee)) |
| ShieldRamp transparent leg (PRD Q4) | Not built |

## Mainnet gate checklist

This is the canonical list; [10 Roadmap](https://sealforge.mintlify.site/roadmap.md) links here. Each item MUST be done before an auction holds mainnet funds.

* [ ] **Trustee-side transaction verification (D1).** Trustees receive the PCZT, check every output against the refund plan derivable from the published result and UIVK (amounts, refund addresses, denominations) and the payout address, and refuse to sign otherwise.
* [ ] **Per-auction value caps**, enforced by the coordinator at creation and shown on the auction page.
* [ ] **Independent trustees**: three different operators on separate infrastructure, not one operator's machines.
* [ ] **External review** of the escrow signing path (FROST over PCZT α, `apply_signatures`) and the DKG relay.
* [ ] **Rate limiting** on public endpoints (Caddy).
* [ ] **CSP decision**: nonce-based strict CSP, or a recorded acceptance of `'unsafe-inline'`.
* [ ] **FROST ciphersuite from an upstream-published crate**, replacing `reddsa =0.5.2` and the deprecated fixed-α `sign` ([3 upstream risk](https://sealforge.mintlify.site/zcash-integration.md#dependencies-and-upstream-risk)).
* [ ] **Clean, reproducible WASM builds (D2)**: every `BUILD.json` with `"source_dirty": false`, reproduced by the CI `wasm` job.
* [ ] **Off-site encrypted backups drilled** on the production host ([evidence/backup-drill.md](https://github.com/Udoka-AM/sealForge/blob/main/docs/evidence/backup-drill.md) lists what isn't drilled yet).
* [ ] **Rescan performance on real blocks** measured for the 3,500-block audit target ([evidence/perf.md](https://github.com/Udoka-AM/sealForge/blob/main/docs/evidence/perf.md)).
* [ ] **Expiry handling for broadcast batches (D3).**


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.