Why do this per change rather than per project
The traditional version is a workshop: a room, a whiteboard, a diagram of the system, half a day. It produces a good document that is out of date in a quarter, and it cannot keep pace with changes arriving several times a day.
The per-change version is four questions and takes two minutes. It is much shallower and it runs on every change, which for a system that changes constantly is the better trade.
Adam Shostack’s four questions frame the whole discipline: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job? Everything below is those four, narrowed to a diff.
The four, narrowed
1. Where does untrusted input enter this change?
List the entry points in the diff. An HTTP parameter, a header, a file upload, a webhook body, a message from a queue, a row in a table that a user populated earlier, an environment variable set from a configuration service, a field in a third-party API response. Anything a person outside your trust boundary influenced.
Most changes have one or two. A change with none is usually fine. A change where you cannot answer quickly is the one to slow down on.
2. What can this code do that its caller should not be able to do?
This is the privilege question and it catches confused-deputy bugs. Does this function run as a service account? Does it hold a token with broader rights than the user? Does it read a file path the user supplied, with the server’s filesystem permissions?
The classic shape: an export endpoint that builds a filename from user input and runs with permission to read everything.
3. Who is allowed to do this, and which line checks it?
Asked as a request for a line number, not a yes or no. “Middleware handles it” is not an answer; “line 42, and it compares invoice.customer_id to session.customer_id” is.
This is the one from earlier in the module, and it stays first among equals because it is both the most common serious defect and the one no tool will find for you.
4. If this is wrong, what does an attacker get?
The blast radius. A wrong answer in a rendering helper is a display bug. A wrong answer in a token comparison is every account. The same defect severity has completely different consequences depending on where it sits, and this question is what tells you how much of the previous three to actually do.
A worked example, briefly
A change adds a CSV export to a reports page.
Untrusted input: the date range, the report type, and a filename the user can set. Privilege: the export job runs as a worker with database read access to all tenants. Authorisation: the page checks the session, and the worker, which runs later, from a queue, does not re-check the tenant. Blast radius: one tenant’s user obtains another tenant’s data.
That is a serious finding, and it fell out of four questions in ninety seconds. Note what produced it: the gap between the request-time check and the queue-time execution. Generated code is particularly prone to this because the two halves are usually generated separately, each correct on its own.
STRIDE as a prompt, not a process
If four questions produce nothing, the older checklist sometimes shakes something loose: Spoofing, Tampering, Repudiation, Information disclosure, Denial of service, Elevation of privilege. Read the six words against the diff. Repudiation is the one people never consider and is why audit logs exist.
Use it as a prompt for thinking. Used as a form to fill in, it becomes a ritual with a box ticked and no thought behind it, which is worse than nothing because it produces a record suggesting the analysis happened.
What this is and is not
Threat modelling has no credible effect-size evidence. There is no trial showing that teams doing it have fewer incidents, and the claims made for it in vendor material are unsupported. What can be said is that the questions are cheap, they direct attention at the classes that scanners cannot reach, and in practice they surface the authorisation gap that everything else misses.
Treat it as a thinking aid with a good track record in anecdote, not a control with measured efficacy. That is an honest description of most security practice, and saying so tends to make people more willing to try it rather than less.
Every lesson here is open. Your progress is recorded once you pass the AI at Work exam.
Check your understanding
In the CSV export example, why did splitting the work between a request handler and a queue worker create the vulnerability?
Pick the one you would defend. Your answer stays private.
Stuck on something?Ask Larissa, your AI tutor
