Most advice on threat modeling assumes a design phase: get the architects in a room, draw the system, find the threats, write it up, then build. Agile teams don't have that phase. The design changes every sprint, and a threat model written in week one describes a system that stops existing by week six. So the model either becomes a document nobody opens, or the team skips threat modeling and finds the design flaws in a penetration test after release.
Neither is necessary. Agile teams don't need less threat modeling. They need it in smaller pieces, sized to each level of the backlog, all writing to one model that stays current. This post covers which epics need a session and which don't, a 15-minute check for stories, what to add to the definitions of ready and done, and a worked epic carried through two sprints.
The short version: keep one living threat model per system (a data flow diagram, attack trees for the goals that matter and a scored risk register), and change it at the size of each backlog item. An epic that adds a trust boundary, a data store, an integration, a role or a new way in gets a 60-minute session before its stories are written. Every story that touches the diagram gets a 15-minute check in refinement: if it matches an existing leaf, copy that leaf's mitigation into its acceptance criteria; if it adds something new, take it back to the epic model. At each sprint review, spend 10 minutes on what changed in the register. Findings go into the feature's own acceptance criteria or into enabler stories, never into a separate security backlog.
Why the big upfront model fails in agile
A threat model done once, up front, has three problems in an agile team. It goes out of date quickly, because each sprint changes the system a little and nobody updates a document they didn't write. It arrives too late or too early: before the epic is refined, there's nothing concrete to model, and after the stories are written, the design has already been decided. And it competes with delivery, because a two-day workshop has to be scheduled around sprints instead of happening inside them.
Agile itself isn't the problem. The Threat Modeling Manifesto values "continuous refinement over a single delivery" and "a journey of understanding over a security or privacy snapshot", which describes how agile teams already work. What changes is the unit of work. Instead of one model per project, you get one model per system and many small changes to it, each sized to the backlog item that caused it. Our post on shifting security left makes the case for doing this at design time. This one is about fitting it into the backlog.
Three sizes of threat modeling, one model
| Level | When | Who | Time | Output |
|---|---|---|---|---|
| System model | Once per system, then kept current | The team, with a facilitator for the first one | About half a day | DFD with trust boundaries, attack trees for the two or three goals that matter most, scored register |
| Epic session | After the epic is understood, before its stories are written | The developers and tester who'll build it, and the product owner | 60 minutes | Diagram changes, new and re-scored leaves, security acceptance criteria, enabler stories, accepted risks with an owner |
| Story check | Backlog refinement | Whoever refines the story | 15 minutes | Acceptance criteria copied from matching leaves, or a flag that the epic model needs another look |
| Register review | Sprint review | The team and the product owner | 10 minutes | What was added, mitigated, accepted or re-scored this sprint |
If you don't have a system model yet, build it before anything else. Our guide to running your first threat modeling workshop covers that session. You only build it once. Everything after that is an edit.
The epic test: which epics need a session
Modeling every epic burns time on work that doesn't change the system's security, and teams soon stop doing it. Modeling none means the design flaws ship. The middle ground is a short test, asked when the epic is first refined. If the answer to any question is yes, the epic gets a session.
- Does it add or move a trust boundary? A new service, a new network zone, a public endpoint for something that was internal.
- Does it add a data store, or a new kind of data to an existing one? Especially personal, payment or health data, or secrets.
- Does it add an external integration, in either direction? A webhook, a third-party API, an import, an export to a partner.
- Does it add a role, or change who can do what? New user types, sharing, delegation, admin tools, support access.
- Does it add a new way in? An endpoint, a file upload, a link sent by email, a public form.
These five questions are deliberately about the system's structure, not about how risky the feature sounds. A "simple" CSV import adds a new way in and a new data path, while a big redesign of the billing page may change nothing the attacker can reach. Our list of re-threat-modeling triggers covers the same idea for changes outside the backlog, such as incidents, new dependencies and changes to infrastructure.
The 60-minute epic session
Hold it once the epic is understood well enough to draw, and before anyone writes its stories. That's the point where a finding can still change the design cheaply: "invites are bound to an email address" is a design decision, not a bug fix, if it's made before the invite flow exists.
- Update the diagram (10 minutes). Open the system's DFD and add what the epic adds: new processes, stores, flows and boundaries. Never start from a blank whiteboard. Starting from the existing diagram is what keeps one model per system.
- Extend the attack tree (20 minutes). Pick the goal the epic makes easier, such as "read another customer's invoices", and add the new paths as leaves. Check the existing leaves too: a new endpoint is often a new place for an old threat.
- Score the leaves (10 minutes). Likelihood and impact on the same risk matrix the rest of the register uses, so the new rows can be ranked against the old ones.
- Turn leaves into backlog items (15 minutes). Each leaf you'll fix becomes acceptance criteria on the story that builds that part, or an enabler story if several stories depend on it. Each leaf you won't fix becomes an accepted risk with a named owner and a review date.
- Write down the assumptions (5 minutes). "Only workspace owners can invite." Assumptions are what the next story check tests against.
The output is a change to the model, not a report. Nobody writes a summary. The diagram, the tree and the register are the record.
The 15-minute story check
Stories are too small for a session, but some stories quietly change what the epic session assumed. The story check is four questions asked during refinement, about stories that touch an element on the diagram:
- Which elements on the diagram does this story touch? If none, stop: there's nothing to check.
- Does it match a leaf already in the tree? If so, copy that leaf's mitigation into the story's acceptance criteria, with a test.
- Does it add anything the model doesn't have? A new flow, a new kind of data, a bigger blast radius for an existing leaf. If so, add or re-score the leaf now.
- Is it bigger than 15 minutes? If the story changes the structure (it would pass the epic test on its own), take it back to the epic model rather than squeezing it into refinement.
This complements abuse cases rather than replacing them. An abuse case describes how one story could be misused, in the story's own words. The story check connects the story to the system model, so a threat found once is reused every time the same element changes, and a story that makes an old leaf worse gets it re-scored.
A worked example: an epic through two sprints
Invoicely is the small invoicing SaaS from our threat model example: a web API, a PDF worker, file storage, a Stripe webhook and a support console. Its system model already exists, with ten scored threats. The top one is T2, an IDOR where a customer reads another customer's invoices by changing the ID (4 × 5 = 20).
The next epic is Team workspaces: a business owner can invite their accountant and staff into a shared workspace, with roles.
The epic test
Two yeses. It adds roles and changes who can do what (question 4), and it adds a new way in, an invite link sent by email (question 5). So the epic gets a session.
The epic session
The team adds a Workspace membership store and an invite email flow to the DFD. Under the goal "someone outside the company reads or changes its invoices or payout details", they add five leaves. One of them isn't new at all: workspace IDs in the API are a new place for T2.
| # | Leaf | L × I | Decision |
|---|---|---|---|
| T2 | A member swaps the workspace ID in an API call and reads another workspace's invoices | 4 × 5 = 20 | Mitigate with an enabler story: one membership check that every workspace endpoint goes through |
| W1 | An invite link is forwarded or reused, and someone else joins the workspace | 3 × 4 = 12 | Mitigate: single-use links, expiry after 7 days, bound to the invited email address |
| W3 | A removed member keeps access through an open session or an API token | 3 × 4 = 12 | Mitigate: removal revokes sessions and tokens at once |
| W2 | The Accountant role can change payout bank details | 2 × 5 = 10 | Mitigate: Accountant is read and export only, following least privilege |
| W4 | Invites are used to send unwanted email from Invoicely's domain | 2 × 2 = 4 | Accept for now, owner: head of product, review in six months |
Assumption recorded: only workspace owners can invite or change roles.
From leaves to stories
No "security story" is written. The leaves become acceptance criteria on the stories that build each part, plus one enabler story that has to land first because three stories depend on it.
| Story | Security acceptance criteria | Closes |
|---|---|---|
| Enabler: every workspace endpoint goes through one membership check | A test calls every workspace endpoint with another workspace's ID and expects 404 | T2 |
| As an owner, I can invite my accountant by email | The link works once, expires after 7 days and only accepts a sign-in with the invited address | W1 |
| As an owner, I can choose a member's role | A test calls each payout and invite endpoint as an Accountant and expects 403 | W2 |
| As an owner, I can remove a member | The removed member's next request with an existing session or token gets 401 | W3 |
Sprint 1 takes the enabler, the invite story and the roles story. Sprint 2 takes the removal story and whatever refinement adds.
A story check in sprint 2
During sprint 2 refinement, a new story arrives: "As an accountant, I can export all the workspace's invoices as a CSV file." It doesn't pass the epic test on its own, so it gets the 15-minute check.
- Elements touched: the API, the invoice store and a new export endpoint. No new boundary.
- Matching leaf: T2. The criterion "the export goes through the membership check, tested with another workspace's ID" is copied in.
- Anything new: two things. Invoice notes are customer-written text, so a note starting with
=becomes a formula when the CSV is opened in a spreadsheet (CSV injection). That's a new leaf, W5, scored 2 × 3 = 6, with the criterion "cells starting with=,+,-or@are escaped". And a one-click export of everything makes W1 worse: a stranger who gets into the workspace can now take all its invoices at once, so W1's impact goes from 4 to 5, and its score from 12 to 15. - Bigger than 15 minutes? No. Done.
The re-score is the part a separate threat-model document would miss. Part of W1's fix had already slipped into sprint 2, and at 15 it now sits level with T5, the support console's shared database role, near the top of the register. That makes it much harder to let it slip again.
The sprint reviews
| Sprint | Register changes |
|---|---|
| Sprint 1 | Added W1 to W4. T2 and W2 mitigated, with their tests in the pipeline. W4 accepted, with an owner and review date. W1 still open: the invite story is done but binding to the email address moved to sprint 2. |
| Sprint 2 | Added W5. W1 re-scored from 12 to 15, then mitigated. W3 and W5 mitigated. The DFD now matches what shipped, including the export endpoint. |
That's the whole security conversation at each review: two minutes of reading rows, plus a decision on anything that slipped. The product owner can see that W1 was carried over and decide whether the epic is done without it.
Definitions of ready and done
The practice only lasts if it's attached to checkpoints the team already respects. Add these:
- Definition of ready, for epics: the epic test has been answered. If any answer is yes, the epic session has happened and its stories carry their security acceptance criteria.
- Definition of ready, for stories: stories that touch the diagram have had the story check.
- Definition of done: every security acceptance criterion has a passing test, including at least one negative test, such as calling the endpoint as another customer.
- Definition of done: the data flow diagram matches what was built.
- Definition of done: the register shows the new status of every leaf the story touched. Accepted risks have an owner and a review date.
The diagram item is the one teams drop first and the one that matters most. If the diagram drifts from the code, the next epic session starts from a system that doesn't exist.
Keeping the model current across sprints
- Update the model in the sprint that changes the system, not in a later "documentation sprint". An update is a few minutes when the change is fresh and an archaeology project six months later.
- Treat open register rows as backlog items. A mitigation that isn't in the backlog doesn't get built. Our post on why risk registers are backlogs covers the argument, and prioritising a backlog of threats covers the ranking.
- Take a snapshot at each release. When an auditor or a customer asks what you knew about a risk when version 3.2 shipped, the answer is the model as it was then, not as it is now.
- Re-check the assumptions now and then. Once a quarter, read the recorded assumptions and ask whether they're still true. "Only owners can invite" stops being true the day someone ships delegated admin.
- Measure it lightly. Count epics that passed the test and had a session, and findings that changed a design before code was written. If the second number is zero for a quarter, the sessions are happening too late. Our threat modeling maturity page has more on what to track.
Where agile threat modeling goes wrong
- The "As an attacker" story. "As an attacker, I want to read other customers' invoices, so that…" sounds clever and is never prioritised, because no product owner wants it delivered. Put the mitigation on the feature story as acceptance criteria instead.
- A separate security backlog. Security tickets in their own queue get triaged separately and finished never. Enabler stories live in the same backlog as features, ranked by the same product owner.
- Modeling every story. If every story gets a session, the sessions become ceremony and stop finding things. The epic test and the 15-minute check exist so most stories cost nothing.
- The sprint-zero model. A model built in the first sprint and never touched again is the waterfall model with extra steps. If the diagram isn't in the definition of done, this is what you'll get.
- Waiting for the security team. If an epic session needs a security engineer to happen, it happens when one is free, which is after the design is fixed. A trained developer or tester can facilitate. Our post on security culture without a dedicated team covers building that habit.
What this doesn't do: it doesn't replace testing. The epic session finds design flaws, not implementation bugs, so you still need code review, scanning and penetration testing for those. Our comparison of threat modeling and penetration testing covers where each fits.
Checklist: threat modeling in an agile team
- Build one system model per system: a DFD with trust boundaries, attack trees for the top goals and a scored register.
- Ask the five-question epic test when each epic is first refined.
- For each epic that passes, hold a 60-minute session before its stories are written, starting from the existing diagram.
- Turn leaves into acceptance criteria on feature stories, or into enabler stories. Never into a separate security backlog.
- Record accepted risks with an owner and a review date, and record the assumptions.
- Run the 15-minute story check in refinement for stories that touch the diagram, and re-score leaves a story makes worse.
- Add the security criteria, the diagram and the register to the definitions of ready and done.
- Spend 10 minutes on the register at each sprint review.
- Take a snapshot of the model at each release.
- Re-check the assumptions once a quarter.
Frequently asked questions
Can you do threat modeling in agile?
Yes, as long as you stop treating it as one big document written before development starts. Keep one living threat model per system, and change it in small steps at each level of the backlog: a 60-minute session for epics that change the shape of the system, a 15-minute check on stories that touch the diagram, and a short look at the risk register at each sprint review. Most sprints then add a few leaves and close a few rows rather than starting over.
How much time does threat modeling take in a sprint?
Less than most teams expect once the system model exists. A typical two-week sprint needs about 15 minutes per story that touches the data flow diagram, done during refinement, and 10 minutes at the sprint review. An epic that adds a trust boundary, a data store, an integration, a role or a new way in gets one 60-minute session before its stories are written. Building the first system model takes about half a day, once.
Should threat modeling be a separate user story?
Usually not. A story called "threat model the invite feature" produces a document, not a safer feature, and it competes with features for priority. Put the work where the change is: the epic session's time comes out of refinement, its findings become acceptance criteria on the feature stories, and a fix that several stories depend on, such as one shared authorisation check, becomes an enabler story with the attack tree leaf it closes named in it.
Who should run threat modeling in a Scrum team?
The team that builds the feature: developers, a tester and the product owner, who decides what risk is acceptable. A security champion or the security team can facilitate, especially for the first few epic sessions, but the session shouldn't wait for them. If threat modeling only happens when a security engineer is free, it happens after the design is fixed.
How does threat modeling fit the definition of done?
Add three checks to the definition of done: every security acceptance criterion has a passing test, including at least one negative test such as calling the endpoint as another customer; the data flow diagram matches what was actually built; and the risk register shows the new status of every leaf the story touched, with accepted risks named, owned and dated. Add one to the definition of ready: an epic that passes the epic test has had its threat model session before its stories are pulled into a sprint.