flowchart LR
user(["Customer<br/><i>untrusted</i>"])
admin(["Admin<br/><i>privileged</i>"])
subgraph edge["Boundary 1 — public edge"]
cdn["CDN / WAF"]
end
subgraph app["Boundary 2 — application tier"]
direction TB
api["Order API"]
auth["Auth Service"]
end
subgraph datab["Boundary 3 — data tier"]
direction TB
db[("Order Store<br/><i>PII + card token</i>")]
kms[("Key Vault")]
end
ext["Payment Provider<br/><i>third party</i>"]
user -->|"F1 HTTPS"| cdn
cdn -->|"F2 HTTPS + mTLS"| api
admin -->|"F3 admin console"| api
api -->|"F4 token introspection"| auth
api -->|"F5 TLS + parameterised"| db
api -->|"F6 fetch DEK"| kms
api -->|"F7 HTTPS outbound"| ext
ext -->|"F8 webhook — signed"| cdnWhat it is
A data flow diagram with trust boundaries drawn across it. The processes, stores and flows are ordinary; the dashed boundaries are what turn it into a security artifact. Every flow that crosses a boundary is numbered, and each numbered crossing gets walked through a threat taxonomy — spoofing, tampering, repudiation, information disclosure, denial of service, elevation of privilege — producing a finding or an explicit "not applicable, because".
When you produce it
At design time, when the mitigation is a design choice rather than a patch, and again whenever a new external integration or a new class of data appears. The inbound webhook in the example is exactly the flow that gets added later and never re-modelled.
Who reads it
Security architects, who drive the session. The engineering team, who must be in the room — a threat model produced without them is a document, not a control. Auditors, who ask to see it and to see what came out of it.
What good looks like
- Flows are numbered and the numbers are referenced by the findings table.
- Boundaries reflect real differences in trust, not diagram tidiness.
- Data sensitivity is annotated on the stores.
- Inbound flows from third parties are drawn — a webhook is an inbound flow from an untrusted source no matter who sends it.
- The output is a findings list with owners, not a picture.
Common mistakes
- No boundaries. Then it is a data flow diagram and the analysis has nowhere to attach.
- Only outbound third-party flows. Callbacks and webhooks are the ones that get missed.
- Modelling the whole estate. Scope it to one system and one release, or it never finishes.
- Producing the diagram and stopping. The diagram is the input; the findings and their owners are the deliverable.