Security Engineering · Threat Modeling
Adversary Capability Models and the Assumptions They Encode
How an attacker profile is really a list of things the attacker cannot do, why network position and time budget dominate the labels, and where capability tiers mislead.
A threat model that says “the adversary is an advanced persistent threat” has said almost nothing operationally. It names a category whose members differ in what they can do by orders of magnitude, and the label’s effect is to make every mitigation look insufficient while indicating none specifically. What the analysis needs instead is an explicit enumeration of what the adversary can and cannot do, because a control is only meaningful as a negation of a specific capability.
A capability model is a list of impossibilities
Cryptographic definitions make this structure visible. A scheme is proven secure against an adversary with a stated budget: polynomial time, a bounded number of queries, access to particular oracles, and no access to others. The security claim is exactly the claim that the adversary cannot distinguish two distributions given those limits. Remove a limit and the claim may fail, which is why the definition is stated in terms of restrictions rather than adjectives.
Threat modeling inherits the same logic informally. For each plausible adversary, the useful questions are: what network position does it hold, what credentials does it already have, how much time will it spend, how much can it spend, and what is it unwilling to do because the action would be detected or would burn an asset it needs later. The last question is the one most often skipped and the one that produces the most useful controls, because many real intrusions are constrained by the attacker’s need to remain unnoticed rather than by any technical barrier.
A model that records these five dimensions for each adversary, and then checks that every claimed mitigation negates one of them, can be argued with. A model that records a tier label and moves on cannot.
Position dominates the label
The single most consequential attribute is where the attacker sits relative to the system’s enforcement points. Three positions recur and behave differently enough that they deserve separate analysis regardless of the label attached to whoever occupies them.
An unauthenticated remote position can reach exposed endpoints and nothing else. Its capabilities are bounded by the attack surface: request parsing, authentication logic, and any endpoint that acts before authentication completes. Most remote compromises start from this position, and the relevant question is not whether the attacker is sophisticated but whether the surface has a defect reachable without credentials.
An authenticated low-privilege position holds a valid identity with limited authority. This is the position of a legitimate user who is hostile, or of an attacker who has obtained one ordinary account. Its capabilities are defined by the authorization model: everything the role permits, plus anything the system fails to check because it assumed the caller was trusted. Broken object-level authorization is the archetype, and it exists precisely because code written for an authenticated caller often omits the ownership check.
A code-execution position inside the trust boundary has already crossed the boundary the diagram drew. Once an attacker runs code as the service principal, the interesting questions change entirely: what credentials are reachable from that process environment, what the process can reach on the network, and what the process is authorized to do. This is where a compromised service becomes a compromised system, and the severity depends on the credential topology rather than on the attacker’s skill.
The labels cut across these positions in ways that mislead. An insider is usually at the authenticated position, which carries more authority than a remote attacker’s, and much less discussed. A well-resourced remote attacker without a foothold is still limited to the exposed surface, however many tools it owns. Position is measurable from the architecture; sophistication is not. Recording a position per adversary also makes the enforcement points explicit, since each position is defined by which trust boundary the adversary has or has not crossed.
The resource dimensions that actually bind
Time is the dimension most often ignored and most often decisive. An attacker with a week can enumerate, test, and return; an attacker with a minute gets one attempt. This is why rate limiting is a genuine control rather than a nuisance: it does not stop any individual request, it removes the ability to iterate. The same reasoning explains why a slow, low-volume credential-stuffing campaign defeats lockout thresholds that are keyed to attempts per account: the attacker spends time instead of attempts.
Money binds differently. Some attacks have a per-attempt cost that is paid to a third party: buying a residential proxy pool, paying for a solving service, renting compute to brute-force a keyspace. Where the attacker’s cost per attempt exceeds the expected value of a success, the attack stops. This yields a control that is not usually described as one: making each attempt expensive. A password hash that takes a fixed fraction of a second per guess, combined with a per-account attempt budget, converts an offline cracking problem into a cost problem, and the relevant parameter is the ratio of the defender’s storage cost to the attacker’s compute cost.
Attention is the third and the least modeled. Most intrusions are not a single clever step but a sequence, and each step requires the attacker to notice something and decide. Detection that fires on the third step of a sequence is worth far more than detection that fires on the tenth, because the earlier signal is cheaper for the defender to act on and the attacker has committed less. This argues for instrumenting transitions between trust zones rather than only ingress, which connects directly to how trust boundaries are placed in the model: each crossing that produces an audit record is a point where the attacker’s sequence becomes visible.
Why the insider is the hard case
The insider is not a more capable remote attacker; the position is structurally different in three ways that break standard controls.
First, the insider’s actions are authorized. Access control answers the question of whether a principal may perform an action, and for the insider the answer is yes. Every control built on denying unauthorized actions is silent. What remains is anomaly detection on authorized behavior, which requires a baseline, and a baseline requires knowing what normal looks like for a specific role at a specific time, which is a statistical claim rather than a rule.
Second, the insider can often observe the monitoring. Anyone who operates a system knows what is logged, how long logs are retained, and which actions trigger an alert. Controls whose effectiveness depends on the attacker not knowing about them fail entirely against this position, which is the same reason Kerckhoffs’s principle applies to cryptography: assume the mechanism is known and rely on the key.
Third, the insider’s access is often legitimately broad because the role requires it. An operator who can restore backups can read every record in them. A support engineer who can act on behalf of users can impersonate any user. The control that helps is not narrower permission but separation of duty plus attribution: split the capability so that no single principal can both perform and conceal an action, and make every action attributable to a specific authenticated principal whose credentials are individual rather than shared.
Stating the assumption and testing it
Every adversary model contains assumptions that, if false, invalidate the analysis. The discipline that keeps a model honest is to write those assumptions down as falsifiable statements and attach each to the mitigation that depends on it.
A model might assume that the attacker cannot read process memory, which supports the claim that a secret held in memory is safe from a remote position. That assumption fails when the position changes to code execution, and the mitigation that depended on it must be replaced rather than supplemented. A model might assume the attacker cannot observe traffic between two services, which supports plaintext transport inside a zone. That assumption fails when the zone is a shared network, and the honest response is to remove the assumption rather than to add a control that depends on it.
The test is mechanical: for each mitigation, name the assumption that makes it work, and ask whether any adversary in the list can violate that assumption. Where the answer is yes, the mitigation is not a mitigation against that adversary, and the model should say so rather than listing it. This is the difference between a threat list that has been reasoned about and one that has been generated. The same discipline applies to the ranking of what is worth attacking in the first place, since an adversary model that names capabilities without naming targets cannot be evaluated at all.
References
- NIST SP 800-30 Rev. 1: Guide for Conducting Risk Assessments — NIST, 2012
- Probabilistic Encryption — Shafi Goldwasser and Silvio Micali, Journal of Computer and System Sciences, 1984
- La cryptographie militaire — Auguste Kerckhoffs, Journal des sciences militaires, 1883
- MITRE ATT&CK Enterprise Matrix — MITRE