CtrlK
BlogDocsLog inGet started
Tessl Logo

testland/stride-threat-modeling

Enumerates security threats against a feature specification or design using Microsoft's six STRIDE categories (spoofing, tampering, repudiation, information disclosure, denial of service, elevation of privilege), each paired with the security property it violates. Covers the asset-and-trust-boundary walk that produces threat rows, the threat-row output schema, a likelihood x impact triage rule labelled plainly as practitioner convention rather than standard, a worked example, and an anti-pattern catalog. Enumerates threats against a design; it does not scan code, run a penetration test, or audit control compliance. Use when a PRD section, user story, design doc, or architecture sketch touching authentication, user data, payments, file uploads, or an external integration is about to enter implementation and no threat model exists for it yet.

75

Quality

94%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Low

Low-risk findings worth noting

Overview
Quality
Evals
Security
Files

SKILL.md

name:
stride-threat-modeling
description:
Enumerates security threats against a feature specification or design using Microsoft's six STRIDE categories (spoofing, tampering, repudiation, information disclosure, denial of service, elevation of privilege), each paired with the security property it violates. Covers the asset-and-trust-boundary walk that produces threat rows, the threat-row output schema, a likelihood x impact triage rule labelled plainly as practitioner convention rather than standard, a worked example, and an anti-pattern catalog. Enumerates threats against a design; it does not scan code, run a penetration test, or audit control compliance. Use when a PRD section, user story, design doc, or architecture sketch touching authentication, user data, payments, file uploads, or an external integration is about to enter implementation and no threat model exists for it yet.

stride-threat-modeling

What this owns, and what it does not

This skill turns "we are adding feature X" into a table of candidate threats against the design of X, classified by STRIDE, each with a named mitigation.

The output is a planning document about a design, not a finding about a system. That boundary decides what belongs here:

Adjacent activityWhat it producesWhy it is not this
Static / dependency / container scanningFindings about code or artifacts that already existRuns against an implementation; this runs before one exists, and every row here is an unproven hypothesis
Penetration testingDemonstrated exploitation with evidence of reachabilityProves a threat is real; this only asserts a threat is plausible and worth designing against
Security-control compliance auditEvidence that a required control is present and effectiveAudits go control to system; this goes threat to proposed control, the opposite direction
Requirements / testability reviewAmbiguity, missing acceptance criteriaVague wording is a requirements defect, not a security finding. Do not launder it into this table

If the design already shipped and you want to know whether it is actually vulnerable, you want a scanner or a tester. This produces the list of things those tools should later be pointed at.

The six STRIDE categories

STRIDE is Microsoft's threat classification, "derived from an acronym for the following six threat categories" (ms-stride); the Microsoft Security Development Lifecycle and its Threat Modeling Tool use the same model (ms-tmt-threats).

Each letter is the negation of one security property. Microsoft's own mapping (MSDN Magazine, Figure 3, "Threats and Security Properties") pairs them as below (ms-stride-approach):

LetterThreatProperty violatedMicrosoft's definition of the threat (ms-stride)
SSpoofing identityAuthentication"illegally accessing and then using another user's authentication information, such as username and password"
TTampering with dataIntegrity"the malicious modification of data", including "unauthorized changes made to persistent data" and "the alteration of data as it flows between two computers over an open network"
RRepudiationNon-repudiation"associated with users who deny performing an action without other parties having any way to prove otherwise"
IInformation disclosureConfidentiality"the exposure of information to individuals who are not supposed to have access to it"
DDenial of serviceAvailability"attacks deny service to valid users"
EElevation of privilegeAuthorization"an unprivileged user gains privileged access and thereby has sufficient access to compromise or destroy the entire system"

The property column is not decoration: the property an attack actually breaks is what tells you whether a candidate row really belongs in that category (ms-stride-approach, Figure 2).

Microsoft is explicit that the classification is not rigorous: the categories cross-correlate, because "escalation of privilege (E) tends to imply spoofing and loss of non-repudiation, and could imply tampering, information disclosure, and denial of service" (ms-dreadful). Do not spend time arguing which letter a threat belongs under. Pick the property the attack actually breaks, record the row, and move on.

Step 1 - Inventory what the design contains

Walk the spec and tag four things. Microsoft's data-flow-diagram vocabulary gives the element types (ms-stride-approach, Figure 4): data flows, data stores, processes, interactors, plus trust boundaries, which are added specifically for threat modeling.

TagWhat to look for in the text
Interactors (actors)Users, admins, third parties, partner services, the attacker. "the end points of your system: the people, Web services, and servers"
Data storesDatabases, tables, buckets, queues, caches, files, secrets, credentials, payment data, PII, session tokens
Data flowsAPI calls, uploads, downloads, webhooks, integrations, batch/cron transfers
ProcessesServices, workers, jobs, request handlers, the thing that actually computes
Trust boundariesbrowser to server, public to private network, non-admin to admin, tenant to tenant, your code to a vendor's

Two sanity rules from the same source keep the inventory honest (ms-stride-approach):

  • No magic sources or sinks. "data isn't created out of thin air. Make sure you have a user represented as a reader or writer for each data store." A store nobody reads means the spec omitted a reader, not that the reader is out of scope.
  • No psychokinesis as transport. "make sure there is always a process that reads and writes data. It doesn't go directly from a user's head to the disk."

Record the inventory before you write a single threat. The completeness of the threat table is bounded by the completeness of this list.

Step 2 - Ask the STRIDE question per element

For each (element x STRIDE category), ask: what is the most plausible threat in this category against this element? Ask it as a question, not as an assertion, which is the form Microsoft recommends ("How can an attacker change the authentication data?", "What is the impact if an attacker can read the user profile data?", "What happens if access is denied to the user profile database?") (ms-stride).

Not every category applies to every element type. Microsoft's threats-affecting-elements matrix narrows the grid before you start (ms-stride-approach, Figure 5):

ElementSTRIDE
Data flowsXXX
Data storesXXX
ProcessesXXXXXX
InteractorsXX

Model the asynchronous surface as well as the synchronous one. Queues, cron jobs, and batch workers are processes and data flows like any other, and the matrix above applies to them identically.

Step 3 - Filter

Drop the intersections where no credible threat exists for this design. A static asset with no service contract has no meaningful denial-of-service row. A read-only page with no write path has no tampering row. An empty cell is a result; a fabricated cell is noise that costs a reviewer real time.

If the inventory turns up no security-relevant assets at all (a copy edit on a public marketing page, for example), the correct output is a statement that no STRIDE-relevant assets were identified. Padding the table to look thorough is the single most common way these documents lose their audience.

Step 4 - Score for triage (practitioner convention, not part of STRIDE)

STRIDE is a classification scheme and carries no scoring rule. Nothing in Microsoft's STRIDE definition ranks or prioritizes threats (ms-stride). The rule below is a practitioner convention for getting a triage order out of a threat table. Treat it as a team agreement you can change, not as a standard you are conforming to.

score = likelihood x impact       # each rated 1 (low), 2 (medium), 3 (high)
                                  # possible scores: 1, 2, 3, 4, 6, 9
ScoreConvention
6 or 9Land the mitigation before ship
3 to 5Backlog candidate
1 or 2May be accepted, with the rationale written down

Two things this is not:

  • It is not DREAD. DREAD is a separate Microsoft risk-rating scheme with five factors: damage, reliability (reproducibility), exploitability, affected users, discoverability. Its co-author has published that the original "rate them from 1-10, add them up, and divide by 5" scoring is "an obvious malfunction", and that at Microsoft "we're NOT using this internally very much. This is NOT how MSRC does things" (ms-dreadful). Do not present the 1-3 rule above as DREAD, and do not import DREAD's factors into it.
  • It is not CVSS. CVSS scores disclosed vulnerabilities in shipped software. A design-stage threat has no confirmed vector to score. Coarse triage is the right resolution here.

Step 5 - Attach a specific mitigation

Every row needs a mitigation that is specific to that asset. Name the concrete control, and cite the verification requirement it maps to so a reviewer can check it later. OWASP's Application Security Verification Standard is the usual anchor: it "provides a basis for testing web application technical security controls and also provides developers with a list of requirements for secure development" (owasp-asvs).

Common threat shapes and their ASVS 4.0.3 anchors (session tokens, broken access control, IDOR, verbose errors, upload storage exhaustion, decompression bombs, polyglot files, executable upload paths) are tabulated in references/mitigations.md.

Output format

# Threat model - <feature name>

**Spec source:** <path or URL>
**Date:** YYYY-MM-DD
**Spec authors should review every row.** A generated threat model is a
starting point, not a sign-off.

## Assets identified

| Asset | Trust boundary | Sensitive |
|---|---|---|
| `users` table (PII) | server-side DB | yes |
| Session token (JWT) | client localStorage to server | yes |
| Profile photo upload | client to object store | partial |

## Threats

| ID | STRIDE | Asset | Threat | Likelihood | Impact | Score | Mitigation |
|---|---|---|---|---|---|---|---|
| T-S1 | Spoofing | JWT | Stolen JWT replayed; attacker assumes user identity | 2 | 3 | 6 | Short-lived access tokens; refresh-token rotation; bind to client fingerprint or mTLS. ASVS 4.0.3 V3.5. |
| T-T1 | Tampering | Upload | Malformed image overflows the image-processing library | 2 | 3 | 6 | Hardened decoder; type by file content, not extension; per-user upload rate limits. ASVS 4.0.3 V12.2.1, V12.1.3. |
| T-I1 | Info disclosure | `users` table | Verbose errors leak DB column names | 2 | 2 | 4 | Generic error to client with a correlation ID; structured logging server-side only. ASVS 4.0.3 V7.4.1. |
| T-E1 | Elevation of privilege | Admin endpoint | Missing role check lets a non-admin call an admin route | 1 | 3 | 3 | Centralize authorization on the service layer; integration test asserts 403 for non-admin tokens on every admin route. ASVS 4.0.3 V4.1.1, V4.1.5. |

Scoring: likelihood x impact, each 1 (low) to 3 (high). Practitioner
convention, not part of STRIDE. 6 and above lands before ship; 3 to 5 are
backlog candidates; below 3 may be accepted with written rationale.

## Open questions for the spec author

<clarifying questions where the walk uncovered ambiguity>

Column notes: ID is T-<letter><n> so rows stay referenceable from tickets and test names. Asset names the specific element from the Step 1 inventory, never a whole subsystem. Threat is one sentence describing the attack, in the attacker's terms. Mitigation names a control plus its verification anchor.

Worked example

A full walk of a profile-photo-upload spec - the Step 1 inventory, the four surviving threat rows with ASVS anchors, and the contrast with a read-only page - is in references/mitigations.md.

Anti-patterns

Anti-patternWhy it failsFix
Generic "use TLS" mitigationsEvery web app already terminates TLS. The row consumes review attention and changes nothingName the specific control for this asset plus its verification requirement
One row per STRIDE category regardless of relevanceTurns the table into a form to be filled in; reviewers stop readingFilter in Step 3. Empty categories are a finding, not a gap
STRIDE-per-element applied mechanically to every elementDozens of rows, uniform and unprioritized, buries the three that matterUse the element matrix to narrow, then rank by score and lead with the top rows
Fabricating threats when the inventory is emptyDestroys trust in every future threat model the team readsState that no STRIDE-relevant assets were identified
Recording spec ambiguity as a security findingVague wording is a requirements defect; filing it here hides it from whoever fixes requirementsPut it under "Open questions for the spec author"
Modelling only the synchronous request pathQueues, cron jobs, and batch workers carry the same threat surfaceInventory async processes and flows in Step 1 alongside request handlers
Presenting the 1-3 score as a standardInvites false precision and cross-team comparison the numbers cannot supportLabel it as a team convention wherever it appears, as the output template does

Limitations

  • A threat model is unproven by construction. Every row is a hypothesis about a design. Confirming exploitability is a separate activity.
  • Completeness is not achievable. Microsoft's own position is that STRIDE was not "developed with any real academic rigor" and that a mitigated model does not prove a system secure, because "frequently threats materialize only when systems are joined to create larger systems" (ms-dreadful, ms-stride-approach).
  • Category assignment is ambiguous by design. The letters cross-correlate (ms-dreadful). Consistency within one document matters; a globally correct assignment does not exist.
  • ASVS requirement IDs are version-scoped. The IDs used above are ASVS 4.0.3. Later ASVS releases renumber chapters, so restate the version wherever a requirement ID appears (owasp-asvs).

SKILL.md

tile.json