Every team that runs a threat modeling workshop eventually asks the same follow-up question, usually a few months after the first diagram was drawn: does this still need updating? Nobody has a good answer. The diagram hasn't been touched since the session. The system underneath it has changed in a dozen small ways nobody tracked against it. And the honest response — "we're not sure, it's probably fine" — is exactly the answer that turns a threat model from a working document into a certificate you drew once and framed on the wall.
The usual fix people reach for is a calendar: review it every quarter. That sounds responsible and produces almost no value, for a reason that becomes obvious the first time you sit through one of these reviews with nothing new to say. The model needs a different kind of clock — one that runs on events in the system, not on the passage of time.
The short version: Don't schedule reviews; watch for ten specific triggers instead — a new externally reachable interface, an auth change, a new class of data, a new integration with elevated access, an architecture change that adds or removes a trust boundary, an incident that matches a branch of your tree, a new compliance driver, an ownership change, an accepted risk's review date, or a step-change in scale. The fast test for whether any given change qualifies: would the diagram itself look different? If a box, an arrow, or a trust boundary would move, revisit it. If the diagram would look identical and only the code inside a box changed, it usually doesn't. Keep a short quarterly check as a backstop for whatever nobody flagged — not a full redo, just a five-minute pass down the trigger list.
Why a calendar alone doesn't work
A quarterly review has two failure modes, and they aren't symmetric. Most quarters, nothing structurally significant happened, and the review becomes a meeting where everyone confirms the diagram still matches reality and the risk register still matches the diagram — genuinely useful the first time, close to worthless the fourth. That's the boring failure. The expensive one is the opposite: something did change, in week three of a thirteen-week quarter, and the model doesn't catch up to it until week thirteen. A new webhook integration goes live, a login flow moves behind a new identity provider, an internal admin tool gets exposed to a partner's network — and for the ten weeks between that change and the next scheduled review, the model everyone is relying on for prioritization and sign-off is quietly wrong.
The fix isn't to review more often — a monthly ritual has the same shape of problem, just compressed. It's to stop treating "has time passed" as the signal at all. The thing that actually invalidates a threat model is a change to what the system does, what it's exposed to, or what it's trusted to protect — and that happens on its own schedule, driven by shipping, not by the calendar.
The ten triggers
None of these require guesswork about what "significant" means. Each is a concrete, checkable event.
| Trigger | What actually changed | Example |
|---|---|---|
| New external interface | A new way in for anyone outside the boundaries already modeled. | A public API endpoint, a webhook receiver, a new mobile deep link. |
| Authentication or authorization change | Who can prove who they are, and what that identity is then allowed to touch. | Adding SSO, changing session length, introducing a new role. |
| New class of data | A category of information the model never assumed the system would hold. | Payment details, health records, a customer's own customer data. |
| New integration with elevated access | A third party or dependency that can now read or act on your behalf. | A new SDK with device access, a Slack app with a write scope, a new vendor with a service account. |
| Architecture change that moves a trust boundary | Something that used to be internal is now reachable from outside it, or vice versa. | Splitting a monolith, moving a job from an internal queue to a public-facing service. |
| An incident or near miss | A real event that tests a branch of the tree, whether it happened to you or a comparable company. | A sector breach that matches one of your assumptions; an internal near miss caught by luck. |
| A new compliance driver | An external party is now going to ask what you modeled and why. | A customer security questionnaire, a new certification, a new regulation in a market you're entering. |
| Ownership change | The person who held the context behind the model's assumptions is no longer the one watching for these triggers. | The engineer who ran the original workshop leaves or changes teams. |
| An accepted risk's review date arrives | A previously accepted risk was conditional on facts that may no longer hold. | "Low priority because this feature has forty users" — and now it has four thousand. |
| A step-change in scale or attractiveness | The same system, but now a more valuable target to attack. | A funding announcement, a large new customer, sudden press coverage. |
A handful of these overlap in practice — a new integration is often also a new external interface, an architecture change often moves data classes around with it — and that's fine. The list isn't meant to be mutually exclusive categories for a spreadsheet. It's meant to be a short, memorable set of questions someone can hold in their head while reading a PR or a design doc.
The fast test: what changed, versus how it changed
Most day-to-day changes to a codebase are refactors: the same inputs, the same outputs, the same trust boundaries, different code underneath. None of the ten triggers fire for those, and they shouldn't — re-running a threat model on every pull request would make the practice unsustainable, which is its own way of killing it.
The test that separates the two: if you redrew the data flow diagram today, would a box, an arrow, or a trust boundary move? A new caller, a new data store, a new external dependency, a boundary that used to sit between two things and no longer does — any of those changes the picture. A change to how a function is implemented, with the same callers, the same data, the same boundaries either side of it, doesn't. This is a question most engineers can answer for their own change in under a minute, which is exactly why it works as a filter someone applies routinely rather than a judgment call escalated to whoever ran the original workshop.
Attach it to a ritual, not a document
A trigger list that lives in a wiki page nobody opens does nothing. It only works pinned somewhere a change already has to pass through — a question in the pull request template, a section in the design doc your team already writes, or, per the shift-left argument, a step at design time rather than a step after the fact. The same applies to who's watching: if your team has a named practice owner rather than a dedicated security function, the trigger list is the concrete thing that role is actually checking for, not an abstract mandate to "keep an eye on security."
When a trigger fires, the update should be scoped to what changed, not a full re-run. A new webhook receiver needs its own entry on the diagram, its own pass through STRIDE, and a look at what it now touches — not a redo of the entire model. Matching the size of the update to the size of the trigger is what keeps this sustainable; treating every trigger as a reason to reopen the whole model is a fast way to make people stop reporting them.
The backstop: a five-minute quarterly check, not a redo
Event-driven triggers have one real weakness: they depend on someone noticing and connecting the dots, and sometimes nobody does. A calendar still earns a place here, just a much smaller one than the quarterly-workshop version. Once a quarter, spend five minutes against the same ten-item list: did any of these happen in the last three months that didn't produce an update? Did an accepted risk's review date pass unnoticed? It isn't a re-modeling session. It's a check for gaps in the event-driven process, which is a different and much cheaper thing than the process itself.
A worked example
A mid-sized SaaS product, two quarters after its first workshop:
- Week 4: a new webhook integration ships, giving a partner service push access to order events. Trigger: new external interface, new integration with elevated access. The team adds the webhook as a new element, runs STRIDE against just that addition, and adds two new entries to the register — not a full re-run.
- Week 9: the engineer who ran the original workshop moves to a different team. Trigger: ownership change. The design-doc template's security section is handed to their replacement explicitly, rather than left to drift to whoever happens to notice it's unowned.
- Week 15: a competitor in the same space discloses an OAuth token-leakage incident. Trigger: sector incident matching a branch of the tree. The team spends twenty minutes checking whether their own OAuth flow shares the same assumption the competitor's didn't test, and confirms it doesn't — a cheap check that closes the question rather than leaving it as background anxiety.
- Week 20: an accepted risk from the original workshop — "acceptable because this admin panel has twelve internal users" — hits its review date. The panel now has ninety users across two customer support teams. The acceptance is revisited and reclassified as a fix, per the prioritization pass that produced it.
- End of quarter: a five-minute check against the trigger list confirms nothing else fired unnoticed. Total time spent across the quarter: under two hours, none of it a full re-run.
Where this goes wrong
- Treating "we haven't had time" as a reason to skip a real trigger. A missed trigger doesn't queue itself for later — it just leaves the model wrong until something else forces the question, usually an incident.
- Full re-runs for small triggers. Re-modeling the entire system because one webhook shipped trains people to under-report triggers, because reporting one feels disproportionately expensive.
- Burying the list in a document nobody consults. A trigger list is only as good as the ritual it's attached to. Unattached, it's a page someone wrote once and nobody rereads until an audit asks for it.
- No named owner watching for them. Ten triggers and nobody whose job it is to notice them is the same as zero triggers — the list existing on paper isn't the same as anyone checking it.
- Confusing "nothing on the list fired" with "nothing changed." The list is a practical filter, not a complete theory of risk. It catches most of what matters cheaply; it isn't a guarantee that a genuinely novel kind of change won't slip past it.
A threat model that's revisited on real triggers, scoped to what actually changed, stays closer to true for less total effort than one reviewed on a calendar and mostly rubber-stamped. The measure of whether this is working isn't how often the model gets touched — it's whether, when something in the system genuinely changes, the model changes with it before anyone has to ask.
Regulated environments tend to generate compliance-driven triggers on a predictable cycle of their own — see threat modeling for fintech and for healthcare for what typically forces a revisit there. The DFD template is a reasonable starting point if the model this list is meant to keep current doesn't exist yet.