Threat Modeling¶
Structured security analysis of the platform, split by surface. Each category page is a self-contained STRIDE pass over one attack surface: its assets, trust boundaries, threats, controls, and residual risk.
Use this section to answer "what could go wrong here, and what stops it?" for a given part of the system. For how a surface works, follow the cross-links to the architecture and operations pages.
Method¶
Each category page follows the same shape:
- Metadata block — created / last-reviewed / next-review-due dates, reviewers, version, surface owner. Every page carries one; see the template below.
- Data flow diagram (DFD) — the entry points, processes, data stores, and the trust boundaries crossed. Elements are numbered (
External entity,Process,Data store,Flow) so threats reference them. - DFD elements — a table naming each numbered element, so the STRIDE rows are traceable.
- Assets and trust boundaries — what is worth protecting and where control changes hands.
- STRIDE — Spoofing, Tampering, Repudiation, Information disclosure, Denial of service, Elevation of privilege. One table per element-class, each row tagged with the DFD ref it applies to: threat → control → residual.
- Findings and recommendations — prioritized, actionable. Rolled up into the register below.
Residual-risk levels: Low (control holds, accepted), Medium (control depends on a convention or has a gap worth closing), High (active exposure — none open at time of writing).
Metadata template¶
Copy this block to the top of every category page and keep the dates current:
| | |
|---|---|
| **Created** | YYYY-MM-DD |
| **Last reviewed** | YYYY-MM-DD |
| **Next review due** | YYYY-MM-DD (6-month cadence, or on any change to the surface) |
| **Reviewers** | name@tomoda.life |
| **Version** | 1.0 |
| **Surface owner** | team / area |
Review cadence. Each surface is re-reviewed every 6 months, or immediately when the surface changes (a new control, a new component, a new trust boundary). Bump Version and the Last reviewed date on any substantive edit; move Next review due forward. A page past its review date is a finding in its own right.
DFD conventions¶
Threat-model pages are the one place in this repo that use Mermaid instead of the dg-* HTML primitives — DFDs are graphs with crossing edges and boundary subgraphs that the box primitives render poorly. Material renders Mermaid natively. Draw each DFD as a ```mermaid flowchart LR:
| DFD element | Mermaid node |
|---|---|
| External entity (E) | stadium E1([E1 · App user]) |
| Process (P) | rectangle P1[P1 · verify token] |
| Data store (D) | cylinder D1[(D1 · user store)] |
| Trust boundary | subgraph name[trust boundary: …] |
| Data flow (F) | edge label -->|F2 ID token JWT| |
Prefer one diagram per path — a single combined graph gets dense fast. Label every edge with its flow id and payload. A flow whose edge crosses into a subgraph is a trust-boundary crossing; those are where most threats live.
Categories¶
| Category | Surface | Last reviewed | Next due |
|---|---|---|---|
| Authentication | Google/Apple sign-in, app vs admin auth paths, oauth2-proxy, Dex, token verification | 2026-08-09 | 2027-02-09 |
More categories are added as surfaces are modeled (secrets & supply chain, network & ingress, data plane). Add a page under docs/security/threat-model/, follow the shape above, and register its findings below.
Findings register¶
Open items across all categories, highest priority first. Close a row when the fix ships; keep the history in git.
| Priority | Category | Finding | Logged | Status |
|---|---|---|---|---|
| Medium | Authentication | Shared OAuth client couples app and admin login; app-side incident can disrupt operator access. Decouple by giving oauth2-proxy/Dex their own client. | 2026-08-09 | Open |
| Medium | Authentication | No CI guard fails a PR that exposes an admin Ingress without the oauth2-proxy middleware. Resolved by policy/admin_ingress_auth.rego (conftest, fail-closed). |
2026-08-09 | Resolved |
| Low | Authentication | pgAdmin/redis-insight record the operator only in the proxy access log (no per-operator attribution). | 2026-08-09 | Open |
| Low | Authentication | Nonce is optional server-side; a client omitting it loses replay protection. Accepted (ID tokens are short-lived). | 2026-08-09 | Accepted |