skip to content

Why keep a threat model as code in pytm or threagile instead of a drawn diagram?

level: middleimportance: must knowfreq 58%

answer

  1. the model lives in a source file
  2. review it like you review code
  3. regenerate on merge, never redraw
  4. one added link, one diff block
  5. everything declared, nothing discovered

basics

~20 s

Because the model becomes a version-controlled source file that diffs in a pull request. pytm's Python and threagile's YAML sit beside the code and regenerate the data-flow diagram and threat report on every run, so the picture never goes stale.

solid answer

~50 s

In pytm you write a Python script that instantiates actors, processes, datastores, trust boundaries and dataflows and sets attributes on them; in threagile you write one YAML file declaring technical assets, communication links, data assets and trust boundaries. Running the tool derives two things from that declaration: a rendered data-flow diagram, and a risk list produced by matching a built-in rule set against the declared attributes. Because the model is a text file, the diff becomes the review signal — on a mortgage-application model, one new `communication_link` from underwriting to an external credit bureau is a block a reviewer can see and question. The output also regenerates on every merge, so nobody re-exports a stale image, and the model sits in the repo's history beside the code it describes. The cost is that the model is only as true as what people write down.

go deeper

for a junior

Be able to say what a pytm or threagile model file contains and that the diagram and threat list are generated from it rather than drawn by hand.

for a middle

Explain the mechanics: you declare elements, flows, boundaries and data assets, and a shipped rule set matches those declarations to emit the risk list. Be clear that nothing is discovered from the code.

for a senior

Show that you review model diffs like code — a new link in the file is a new exposure to question — and that regeneration is wired into the merge so no artifact is ever exported by hand.

for a principal

Own the tradeoff: a source-defined model buys auditability and per-commit history, but it pushes maintenance onto delivery teams and its output is only as honest as the assertions engineers are willing to write down.

## What threat model as code means A threat model as code is a system model written as a source file that a program reads. The elements, the flows between them, the trust boundaries and the data those flows carry are **declared** by a human, and a tool **derives** the diagram and the threat list from that declaration. Two open-source projects define the category. **pytm** (an OWASP project) is a Python framework. You write a script that instantiates objects — a `TM` for the model itself, `Actor`, `Server`, `Process` and `Datastore` for elements, `Boundary` for trust boundaries, `Dataflow` for each link, `Data` for the payloads — and set attributes on them (what protocol a flow uses, whether it is authenticated, whether a store is encrypted at rest). Running the script emits the output. **threagile** is a Go tool driven by a single YAML file. The file declares `technical_assets`, the `communication_links` between them, `data_assets` with their confidentiality and integrity ratings, `trust_boundaries` and `shared_runtimes`. You run the tool over that file and it emits its output. ## Declared versus generated This distinction is the whole subject, and it is where candidates most often go wrong. **Nothing is discovered.** Neither tool inspects your source code, your infrastructure or your running system. Every element, every link and every security attribute is something a person typed. What the tool generates from it: - **A data-flow diagram**, laid out from the declared elements, links and boundaries. - **A threat or risk list**, produced by matching a shipped rule set against the declared attributes. pytm ships a threat library whose entries carry conditions over element attributes; threagile ships a set of risk rules. A rule fires when the model shows the shape it looks for — a link crossing a trust boundary without authentication, a datastore holding high-confidentiality data without encryption at rest, an asset reachable from the internet. - **A report** in a readable format, plus machine-readable output. The decisive property is that the output is a **pure function of the model file**. Run it twice on the same file and you get the same diagram and the same risk list, in the same order. That determinism is what makes the rest work. ## What that buys you over a drawing **1. The diff is the signal.** A drawn diagram changes as an opaque image; a model file changes line by line. On a mortgage-application service, a pull request that adds one `communication_link` from the underwriting service to an external credit bureau is a small, visible block in the diff. A reviewer can immediately ask the questions that matter: which data assets ride that link, does it carry applicant personal and financial data, what protocol and authentication are declared, does it leave the trust boundary the rest of the service sits inside. A new third-party egress of personal financial data has become a reviewable event rather than something discovered a year later. **2. The artifact cannot lag the model.** An e-scooter fleet's telemetry ingest changes constantly — new brokers, new regional endpoints, new consumers of the location stream. If the model regenerates on every merge, the diagram and the report that describe the fleet's availability risks are always the ones the current model produces. Nobody has to remember to re-export a picture. Note the careful wording: regeneration keeps the output true to the **model**, not to reality — that gap is a separate problem. **3. It lives where the change lives.** Same repository, same review, same history, same ownership rules. You can check out the commit that shipped an incident and see the model as it stood. **4. It runs unattended.** The model can be evaluated on every commit, so a report exists continuously rather than for the one quarter someone held a workshop. (The mechanics of the pipeline that runs it, and any decision to fail a build on the result, belong to the delivery and policy layers, not to the model.) **5. Consistency.** Ten teams using one rule set and one vocabulary produce comparable output; ten teams with whiteboards do not. ## What it costs - **Truth is manual.** The file records assertions. If an engineer writes that a link is encrypted, the report believes it. - **The rule sets are generic.** They find the shapes they encode, from declarations; the judgment about business impact and about assumptions that were never true is human work. - **Text is not a whiteboard.** Engineers who reason visually contribute less to a file than to a drawing, and the model can quietly become one person's property. - **Someone must maintain the dialect.** Reviewers have to be able to read the model, or the diff stops being reviewed and becomes noise scrolled past. ## The shape of a model file Roughly, in either tool: trust boundaries: internet | fleet-backend | third-party technical assets: scooter-telemetry-gateway, ingest-service, telemetry-store, underwriting-service communication links: gateway -> ingest-service (protocol, auth, data carried) ingest-service -> telemetry-store data assets: location-stream (confidentiality, integrity, availability ratings) Everything the report says is derived from those four kinds of statement. A threat model as code is best understood as a durable, machine-readable record of a design conversation — not a replacement for having one.

  • A pull request on a mortgage-application threagile model adds one communication link from underwriting to an external credit bureau. What do you do with that diff?
    Treat the added link as the review. Ask which data assets it carries — applicant personal and financial data is the likely answer — what protocol and authentication are declared, and whether it crosses the boundary out to a third party. Then read the risks the rerun produced for that link. A one-block YAML change has introduced third-party egress of regulated personal data, and this diff is the only moment it is cheap to question.
  • In pytm and threagile, which parts of the output are generated and which are asserted?
    Everything about the architecture is asserted: elements, links, boundaries, data assets and every security attribute on them. Generated output is the data-flow diagram, the risk list produced by matching the shipped rule set against those assertions, and the report. Neither tool reads your source code or your deployment, so the generated half is only a restatement of the asserted half plus the rules.
  • What stops a source-defined model from rotting the way a wiki diagram does?
    Two things. The output is regenerated from the file, so the diagram can never disagree with the model; and the file sits on a reviewed path in the repo, so a change to the architecture that skips the model shows up as a design change with no model change beside it. Neither mechanism can tell you whether the assertions in the file were ever true of the running system.

It is the difference between a photograph of a building and its blueprint file: the photo has to be retaken every time something changes, while the blueprint is edited, diffed and re-rendered.

saying these in an interview costs you the question

  • Thinks the tool discovers the architecture by scanning code
  • Says the generated diagram proves the design is secure
  • Treats the model file as documentation nobody reviews
  • Claims model as code replaces the design discussion
  • Believes the report reflects the deployed system

context