# Threat Modelling

Takes a system as it is built and produces the model of how it can be attacked — so the team responsible for it knows what it defends, with what, and what is still exposed.

## Deliverable

One Markdown document, `threat-model.md`, in the structure set out under **Output** below. It is the input to **Security Review of a Change**, which checks new work against the boundaries this document draws.

## Required inputs

- **The system's architecture** — the components, data stores, network positions and the calls between them, from documentation, diagrams or the code itself.
- **What the system protects** — the data and the capabilities that matter, named by someone who owns them.
- **Confirmation that the system is yours to defend** — this skill models a system the reader is responsible for. Without that confirmation it does not run.

If any of the three is absent, stop and report what is missing. Never infer what a system protects from its schema: a table shows what is stored, not what the organisation would lose.

## Optional inputs

- Deployment topology, network segmentation, and the environments the system runs in
- The authentication and authorisation design, including how sessions and tokens are issued
- Existing security controls and the evidence that each one works
- Data classifications, retention rules and regulatory obligations
- Past incidents and test reports, with the remediation status of each finding
- Third-party services the system depends on, and what each one is trusted with

Every optional input that is absent becomes an entry under **Open questions**. Any control that could not be checked is recorded as `assumed` rather than dropped.

## Execution

**1 — List the assets and what each is worth.** For each asset: what it is, where it lives, who owns it, and what the organisation loses if it is disclosed, altered or unavailable. An asset with no named owner is recorded `owner unknown`, because an asset nobody owns is an asset nobody defends.

**2 — Draw the trust boundaries.** A boundary is any place where data or control passes between parties with different levels of trust — a network edge, a process edge, a tenant edge, a change of privilege. For each boundary: what crosses it, in which direction, and what is checked on the way through.

**3 — Enumerate the entry points.** Every route by which input reaches the system, including the ones that are rarely listed: administrative consoles, scheduled jobs that read shared storage, message queues, webhooks, file uploads, support tooling, and the build and deployment path. Tag each `observed` if it was found in the system, or `reported` if a person stated it.

**4 — Derive the threats boundary by boundary.** For each boundary work through the categories in turn — identity claimed falsely, data altered in transit or at rest, an action denied afterwards, information disclosed, capacity exhausted, privilege raised. A systematic pass finds the threat nobody remembered; a brainstorm finds the threat everybody already fears.

**5 — Record the existing controls and how you know.** For each threat, the control that currently addresses it, where that control lives, and whether it is `verified` — you exercised it or read the code that enforces it — or `assumed` — someone said it was there. A control marked `assumed` is not a mitigation; it is an open question with a reassuring name.

**6 — State the residual risk and give it an owner.** For each threat still standing after its controls: what remains, how it would be noticed if it happened, and who owns the decision to accept it or fund it. Residual risk with nobody against it is reported as unowned, never as accepted.

**7 — Collect what could not be determined.** Every asset, boundary or control the material did not settle, each with what it blocks and who can answer it.

## Output

`threat-model.md`, in this order:

- **1. Scope and date** — which system was modelled, from what material, by whom, and when
- **2. Assets** — one line each: asset, location, owner, and what its loss would cost
- **3. Trust boundaries** — one line each: boundary, what crosses it, direction, what is checked
- **4. Entry points** — one line each: entry point, the boundary it crosses, `observed` or `reported`
- **5. Threats** — per boundary: the threat, the category it came from, the entry point it uses, the asset it reaches
- **6. Controls** — per threat: the control, where it lives, `verified` or `assumed`, and the evidence
- **7. Residual risk** — what remains after controls, how it would be detected, the owner, and whether it is accepted
- **8. Assumptions** — every statement taken on trust, and what would confirm it
- **9. Open questions** — the question, what it blocks, who can answer it

## Validation

The model is ready when all of these hold:

- Every asset in section 2 names an owner or reads `owner unknown`
- Every entry point in section 4 maps to a boundary in section 3
- Every threat in section 5 names the boundary it crosses and the asset it reaches
- Every control in section 6 is marked `verified` or `assumed`, with nothing left unmarked
- Every residual risk in section 7 has an owner and a way it would be detected
- No control is described as effective without the evidence that it is

Fail the run if a control appears with neither `verified` nor `assumed` against it, or if a threat is recorded as mitigated on the strength of an assumed control.

## Failure handling

- **No architecture supplied** — stop. Report that the model has no system to describe, and that inferring one from a single component produces a map of that component rather than of the system.
- **Nobody can say what the system protects** — produce sections 3 and 4 from what is observable, leave section 2 empty and marked `pending owner input`, and state that a model without assets ranks nothing.
- **Architecture and code disagree** — record both, name both sources, model the behaviour that is in the code, and raise the disagreement in section 9 as blocking. Do not resolve it by choosing.
- **No access to the running system** — mark every entry point `reported` and every control `assumed`, and state plainly that nothing in the document was verified.
- **Partial material** — model the parts the material supports, mark the rest `INCOMPLETE — pending <question>`, and deliver. A model honest about its edges is usable; one that guessed at them teaches the team to trust a boundary that may not exist.
