Every later chapter in this book answers one question about one kind of attack. This chapter is about the habit of mind that decides which questions matter: what are we protecting, from whom, through which doors, and how bad would it be if we failed. Security people call that habit threat modeling. It is less a document than a way of looking at a design before somebody else looks at it for you.
Common mix-up: a vulnerability is not a risk, and a severity score is not a priority. A flaw rated 9.8 out of 10 in a program that no attacker can reach may matter less to you than a 6.5 in your login page that criminals are using this week. Risk is always about your system: who can reach the flaw, how likely they are to try, and what it would cost you.
Before you start: this chapter assumes you know what a network is and how a home network hangs together. If those are hazy, read What a network is and Your home network on networks.jelia.nyc first.
Security arguments go in circles when people use the same word for different things. "That's a big threat" might mean a skilled criminal group, a bug in the code, or the chance of losing a million dollars. The Internet Security Glossary, RFC 4949, pins the words down, and this book uses its meanings throughout.
Start with the thing worth protecting, the asset: customer records, the money in an account, the ability of a booking system to stay up. A threat is a potential for harm to that asset: someone or something with the capability and a reason to cause it. A vulnerability is a flaw or weakness in the design, the code or the way the system is run that a threat could use. An exploit is the specific technique or piece of code that turns a vulnerability into actual access, and an attack is the attempt itself. When an attack, or an accident, actually breaks the security rules, that is an incident.
Risk ties them together. RFC 4949 defines it as an expectation of loss: the probability that a particular threat will exploit a particular vulnerability with a particular harmful result. Notice the three "particulars." Risk is never a property of a bug on its own. A wide-open window is a vulnerability; whether it is a big risk depends on whether it is on the ground floor, what is in the room, and whether anyone has been trying windows on your street.
| Word | What it means | In the house | In a web shop |
|---|---|---|---|
| Asset | Something worth protecting | The jewelry box | The customer database |
| Threat | A potential source of harm, with capability and motive | A burglar working the neighborhood | A criminal group selling stolen card data |
| Vulnerability | A weakness that could be used | A back window with a broken latch | A search box that builds database queries from raw text |
| Exploit | The concrete method that uses the weakness | Lifting the window from outside | Input crafted to change the query's meaning (Chapter 13) |
| Risk | Likelihood that a threat uses a weakness, times the harm | How likely a break-in is, and what you'd lose | How likely a breach is, and what fines, refunds and trust it costs |
| Control | Anything that reduces the risk | Fix the latch, add an alarm, buy insurance | Parameterized queries, monitoring, encryption at rest |
| Incident | A security rule actually broken | The jewelry is gone | Records were copied out |
What does "harm" mean, though? The classic answer is three properties, the CIA triad. Confidentiality: only the right people can read it. Integrity: nobody can change it without permission, and you can tell if they did. Availability: it works when it is needed. Three more come up so often that most threat modelers add them: authenticity (you are talking to who you think you are), non-repudiation (someone cannot credibly deny an action they took), and authorization (each party can do only what it has been allowed to do).
That list of six properties is the key to the most widely used threat checklist, STRIDE, described by Microsoft engineers Loren Kohnfelder and Praerit Garg in 1999. Each letter names one way to break one property. Once you see the pairing you never need to memorize the acronym again.
| Letter | Threat | Property it violates | Plain example | Typical control |
|---|---|---|---|---|
| S | Spoofing | Authenticity | Signing in as somebody else with a stolen password | Strong authentication (Ch 04) |
| T | Tampering | Integrity | Changing the price in an order on its way to the server | Integrity checks, signatures, TLS (Ch 02, 03) |
| R | Repudiation | Non-repudiation | "I never approved that refund," and no log can show otherwise | Trustworthy, tamper-evident logs (Ch 17) |
| I | Information disclosure | Confidentiality | An error page that prints other customers' details | Encryption, access control, careful error handling |
| D | Denial of service | Availability | Flooding the checkout page until it falls over | Capacity, rate limits, filtering (Ch 09) |
| E | Elevation of privilege | Authorization | An ordinary user reaching the admin-only refund function | Authorization checks, least privilege |
RFC 4949 itself warns that "threat" is frequently misused to mean either a threat action or a vulnerability. The confusion has consequences. A team that says "we fixed the threat" after patching a bug has removed a vulnerability; the people who wanted to get in are still there and will look for the next one. A team that says "the risk is critical" because a scanner reported a critical vulnerability has skipped the part where somebody asks whether the vulnerable component is even reachable.
The same glossary lists four ways to deal with a risk once you have found it, taken from NIST's risk guidance: avoid it (remove the feature or the weakness), limit it (add controls that reduce the likelihood or the harm), transfer it (insurance, or a contract that makes someone else carry the loss) or accept it (decide, in writing, that it is not worth the cost to fix). Accepting a risk is a legitimate decision. Not noticing one is not.
Threat modeling sounds like a specialist ritual with special software and long reports. At heart it is four questions, written down in 2020 by a group of practitioners as the Threat Modeling Manifesto:
The cheapest moment to ask them is before the code exists. Moving a database behind a second network boundary costs a line on a whiteboard during design and a migration project after launch. That is why the manifesto calls threat modeling something you do continuously, alongside design, not a report you write once for an auditor. A good session takes an hour, involves the people who are building the thing, and produces a short list of changes and a sketch that the next person can update.
You also do not need to imagine every possible attacker. It helps to sketch a few threat actors by capability and motive: an opportunist running automated scans across the whole internet; a criminal group after resellable data; a disgruntled insider who already has an account; a well-funded group that wants your organization in particular. Each one sets a different bar. A family photo site mostly needs to beat the opportunist. A payments company has to plan for the criminal group. Naming the actor keeps the conversation honest about how much effort an attack is worth to someone.
STRIDE is a way of answering question 2 for security. Other checklists answer it for other concerns: LINDDUN, from KU Leuven, does the same job for privacy threats such as linkability and identifiability. Attack libraries such as MITRE ATT&CK catalog the techniques real intruders have been seen using, which helps you test whether your list of threats is realistic; Chapter 17 uses ATT&CK to organize detections.
The OWASP threat modeling pages and the OWASP Threat Modeling Cheat Sheet walk through a lightweight process step by step. Adam Shostack's book Threat Modeling: Designing for Security (Wiley, 2014) is the standard long treatment, and the source of the "four question" framing that the manifesto adopted.
The usual model is a data-flow diagram (DFD). It has only four kinds of element, and the shapes are conventional so anyone can read one:
Then comes the step that does most of the work: draw trust boundaries. A trust boundary is a line between parts of the system that trust each other to different degrees, such as the internet and your web server, or your web server and your database. The internet can send your web app anything at all. Your database should only ever hear from your own code.
Every data flow that crosses a boundary from less trusted to more trusted is a place where something must be checked: who is this (authentication), are they allowed (authorization), and is this input what we expect (validation). Flows that stay inside one zone matter too, but the crossings are where attackers enter and where controls give the most value for the least effort. If a sketch has no trust boundaries, it is a network diagram, not a threat model.
With the diagram drawn, STRIDE becomes mechanical. Microsoft's Security Development Lifecycle uses a table called STRIDE-per-element: each kind of element is exposed to a fixed subset of the six threats. You walk the diagram element by element and ask each applicable question.
| Element | S | T | R | I | D | E | Why |
|---|---|---|---|---|---|---|---|
| External entity | ✓ | ✓ | You can't change its insides; it can be impersonated, and it can deny what it did | ||||
| Process | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Code you run is exposed to everything |
| Data store | ✓ | (✓) | ✓ | ✓ | Data at rest can be changed, read or made unavailable; R applies when the store is a log | ||
| Data flow | ✓ | ✓ | ✓ | Data in motion can be changed, read or cut off |
Here is a small online shop at example.com, drawn as a data-flow diagram with its three trust zones. Click or tap any element or numbered flow (or use the buttons under the diagram) to see which STRIDE threats apply to it under the per-element rules, then tick the controls you would put in place. The tally counts every unmitigated threat in the whole system by category, and how many sit on flows that cross a trust boundary. Try "TLS everywhere" to watch one control close a dozen threats at once.
Ticking a control anywhere ticks it everywhere it applies: "TLS on internet-facing connections" protects three flows at once. Nothing here touches a network; it is a model running in your browser.
A threat model is only as good as its diagram, and real diagrams are bigger: a content delivery network in front of the web app, a message queue, a single sign-on provider, a build pipeline that deploys the code. Each new element brings its own row of STRIDE questions. The build pipeline is a favorite blind spot: if someone can tamper with it, every process it deploys is tampered with too. Chapter 16 is about exactly that.
The per-element table is a starting point, not a law. A data flow can be spoofed if the receiver does not check where it came from, so many teams ask all six questions of anything that crosses a trust boundary. And the table only finds threats to the elements you drew. The most expensive misses are usually elements nobody drew: the forgotten test server, the vendor's remote-support account, the spreadsheet export that lives on a laptop.
STRIDE asks "what can go wrong with each part?" An attack tree asks the same question from the other side: "what does the attacker want, and what are all the ways to get it?" Bruce Schneier popularized the idea in a 1999 article in Dr. Dobb's Journal. The attacker's goal sits at the root. Underneath it are the different ways to achieve it, and underneath each of those, the steps it takes, broken down until each leaf is a single concrete action.
Nodes come in two kinds. An OR node is satisfied by any one of its children: to read the database you could steal an admin's login or break the web app or find a stray backup. An AND node needs all of its children: stealing an admin's login only works if you get the password and get past the second factor and can reach the database's network.
Now put a number on each leaf: what it would cost the attacker in money, time or skill. The tree turns into arithmetic. An attacker who is rational about effort pays the cheapest way through, so an OR node costs the minimum of its children and an AND node costs the sum.
A worked example, with the numbers from the instrument below. Logging in as an admin is an AND of $2,000 (phish the password) + $500 (talk past the second factor, which is easy if it is a text message the admin can be tricked into reading out) + $1,000 (get onto the database network): $3,500. Breaking the web app is an OR of a known unpatched flaw ($3,000) and finding a new injection flaw ($15,000): $3,000. Finding a backup is an AND of finding an open storage bucket ($1,500) and reading the unencrypted file inside ($100): $1,600. Bribing an insider: $50,000. The root is the minimum of $3,500, $3,000, $1,600 and $50,000, so the cheapest attack costs $1,600, and it goes through the backup.
That is the lesson attack trees teach better than anything else. The backup was nobody's idea of the front door, and it was the cheapest way in. Fixing the expensive branches first, however satisfying, does not change what the attacker pays. Encrypt the backups and the cheapest path re-routes to the unpatched web app at $3,000. Patch that and it moves to the admin login at $3,500. Defense is the work of raising the minimum.
The goal is to read example.com's customer database. Toggle defenses and watch the attacker's route jump to the next cheapest branch. Every leaf's cost and chance of success is editable in the table under the tree; the program recomputes the whole tree from the leaves up on every change. Switch to "most likely" to rank routes by probability instead of cost: then an OR node takes its most likely child and an AND node multiplies its children's chances.
Nobody knows exactly what phishing one particular administrator costs. The numbers on a real attack tree are estimates, often just "cheap, moderate, expensive" or "needs special equipment: yes or no." That is fine, because the tree's main job is comparative. If two branches differ by a factor of ten, a rough estimate is enough to see which one to defend first.
Schneier's article also points out that leaves can carry yes/no properties rather than costs, such as "requires physical access" or "legal," and you can prune the tree for a particular attacker. An opportunist will not bribe anyone; a determined group might. Pruning by attacker capability is how the threat actors from the previous section plug into the tree.
Two cautions. Costs along an AND branch only add if the steps are independent; in practice one stolen laptop may satisfy several leaves at once. And probabilities only multiply if the events are independent, which is rarely exactly true. The tree is a thinking tool, not an actuarial table.
The attack surface is the sum of all the places an attacker could try to get in or get data out. For software it has four main parts:
Shrinking the surface is often the cheapest control there is, because a door that does not exist does not need a lock, a patch schedule or monitoring. Turn off the legacy API version nobody calls. Remove the admin console from the public internet. Delete customer data you no longer need. Retire the shared "support" account.
A worked example on the shop from Instrument 1. Before cleanup: 3 public web endpoints for customers, 2 old API versions still answering, an admin console on the internet, a file-upload feature used by one partner, 9 administrator accounts and 4 service accounts with database access. That is 7 internet-facing entry points and 13 privileged identities. After cleanup: the two old API versions switched off, the admin console reachable only through an identity-aware proxy (Chapter 11), the partner moved to a separate upload service, administrators cut to 3 named people and service accounts to 2 with narrowed rights. Now 3 internet-facing entry points and 5 privileged identities. No new security product was bought, and the number of things that can go wrong fell by more than half.
| Part of the surface | Count it by | Shrink it by |
|---|---|---|
| Network entry points | Listening services reachable from each zone | Default-deny filtering between zones (Ch 05) |
| Application entry points | Routes, API endpoints, upload handlers, parsers | Remove unused features and old API versions |
| Reachable code | Code an unauthenticated request can execute | Authenticate first, parse later; fewer dependencies (Ch 16) |
| Exposed data | Records reachable through each entry point | Keep less, for less time; split sensitive data out |
| Privileged identities | Admin, service and API-key accounts | Fewer, named, scoped, with strong authentication (Ch 04) |
Attack surface is not a number you compute once. Each release adds routes, each new vendor adds an integration, each new hire adds an account. The OWASP Attack Surface Analysis Cheat Sheet suggests treating it as something you track over time, and flagging changes that grow it, such as a new endpoint that accepts files or a new admin role, for an extra look in code review. That turns threat modeling from an annual event into a reflex attached to every change that matters.
You will always find more threats than you can fix. The point of risk assessment is to put them in order. NIST's Special Publication 800-30, Guide for Conducting Risk Assessments (Revision 1, 2012), lays out the vocabulary most organizations use: a threat source with some capability and intent carries out a threat event, which succeeds if there is a vulnerability and the existing controls don't stop it. The likelihood of that, combined with the impact if it happens, gives the risk.
Most teams can't put defensible dollar figures on either factor, so they use a qualitative risk matrix: a grid with likelihood on one axis and impact on the other, each scored from 1 (very low) to 5 (very high). Each risk becomes a dot. The top-right corner, likely and severe, gets fixed first; the bottom-left gets accepted and watched.
Matrices are popular because they are quick and they start the right conversation. They also have real limits, and it is worth knowing them before you trust one:
Used with those limits in mind, a matrix is a good way to turn a long threat list into a short, ordered work plan, and to make the decision to accept a risk explicit rather than accidental.
Eight risks for the example shop sit on a five-by-five grid. Drag a numbered dot to where you think it belongs, or select it with a button and move it with the arrow keys while the grid has focus. The list underneath re-ranks on every move by likelihood × impact. Then apply a control and watch it move several dots at once: that is how one well-chosen fix can outrank three narrow ones.
Most vulnerabilities you will deal with are not ones you found yourself. They arrive as advisories about software you use, and three public systems describe them.
None of the three knows anything about your system. The CVSS base score describes the flaw in the abstract, so a Critical rating on a component that is unreachable in your design is less urgent than a Medium on your internet-facing login that appears in KEV. That is the common mix-up from the top of the page, and it is how teams end up patching in score order while the exploited bug waits its turn.
A practical ordering that follows from this chapter: first, anything in KEV that is reachable from outside a trust boundary; then high-severity flaws on internet-facing entry points; then the same flaws deeper inside, where an attacker would need another foothold first; then the rest by score. Shrinking the attack surface, the previous section's lesson, moves items down this list without patching anything.
CVSS was always meant to be adjusted. Beyond the base metrics it defines threat metrics (is exploit code available or is it being exploited?) and environmental metrics (how important is confidentiality, integrity or availability for this asset, and do your controls change the picture?). The CVSS v4.0 specification describes how these modify the base score. In practice many organizations only ever look at the base number, which is exactly the part that knows least about them.
FIRST also publishes EPSS, the Exploit Prediction Scoring System, a model that estimates the probability a vulnerability will be exploited in the near future from observed activity. Severity (CVSS), observed exploitation (KEV) and predicted exploitation (EPSS) are three different inputs. Your own exposure, from your diagram and your attack surface, is the fourth, and it is the one only you can supply.
Look back at the attack tree and the STRIDE tally and two design principles fall out, both old and both still the most useful ideas in the field.
Defense in depth. Every control fails sometimes: a patch is late, a password is phished, a rule is mistyped. So build layers that fail independently, and arrange them so an attacker has to beat all of them, an AND node in their tree, rather than any one of them, an OR node. RFC 4949 describes it as layered and complementary mechanisms, so that if one is defeated, others behind it still provide protection. Safety engineers draw it as slices of Swiss cheese: every slice has holes, but the holes rarely line up. In the shop, MFA on admin logins, the database on its own network segment (Chapter 5), encrypted backups and alerting on unusual queries (Chapter 17) are four slices.
Least privilege. Give every person, process and account the minimum access it needs to do its job, and nothing more. Jerome Saltzer and Michael Schroeder listed it among their design principles in 1975, and RFC 4949 defines it the same way today. In STRIDE terms it caps the damage of every E; in attack-tree terms it makes many leaves useless even when they succeed. The web app's database account that can read and write rows but cannot drop tables, the admin role that can refund but not export the customer list, the API key that works for one service only: each one turns a potential disaster into a contained incident.
Assume breach. Put the two together and you get a mindset: design as though some attacker is already inside, because eventually one will be. That changes questions. Not only "how do we keep them out?" but "if this web server were taken over tonight, what could it reach, and how would we notice?" The answers lead to segmented networks (Chapter 5), access decided per request rather than per network location (Chapter 11), logging and detection that watch the inside (Chapter 17), and a rehearsed plan for when it happens (Chapter 18).
And finally, rank. You cannot fix everything, so do this in order: shrink the attack surface where it is free; put controls on every flow that crosses a trust boundary; raise the cheapest branch of the attack tree, then the next; patch what is known to be exploited and reachable before what merely scores high; and write down the risks you accept, with a date to look at them again. That last step, revisiting, is the fourth manifesto question in practice: did we do a good enough job?
The NIST Cybersecurity Framework (version 2.0, 2024) organizes a whole security program into six functions: Govern, Identify, Protect, Detect, Respond and Recover. Threat modeling and risk assessment are the core of Identify: knowing your assets, your threats and your risks. Every other function depends on it. You cannot protect what you have not identified, and you cannot detect an attack you never imagined.
The NIST zero trust architecture guide, SP 800-207, is in a sense "assume breach" written as an architecture, and Chapter 11 takes it apart properly.