Part 3 in a series on medical device software engineering practice.
Most threat modeling articles spend their first thousand words explaining what spoofing is. This one does not. If you are reading about STRIDE-per-Element, you already know the six threat categories, and you already know what a data flow diagram is. What you probably do not have is a defensible answer to the question a reviewer will actually ask:
How do I know you considered the threats that aren’t in this document?
That is the question this article is about.
1. The element-type matrix is a coverage contract, not a checklist
STRIDE-per-Element exists because different element types attract different threats. The MDIC/MITRE Playbook for Threat Modeling Medical Devices describes the method as having been developed by analyzing which STRIDE threats tend to apply to which kinds of element — external entities, processes, data stores, and data flows. The result is the familiar grid: four element types down, six threat categories across, with marks in the cells where that threat class historically applies.
Teams treat that grid as a checklist. Fill the marked cells, ship the document.
That is the wrong reading. The grid’s real value is not the cells it tells you to fill — it is that it makes absence auditable. Before the matrix, a threat model was a list, and a list has no defined shape, so you cannot tell what is missing from it. After the matrix, the model has a shape. Every cell either contains analysis or it does not, and both states are now visible.
A cell, for the rest of this article, means one element instance against one threat category: not the twenty-four cells of the abstract grid, but one row of the grid applied to one actual process, store, flow, or entity in your DFD. That includes the cells the grid leaves unmarked. The grid says Spoofing does not historically apply to a data flow; it does not say Spoofing does not apply to your data flow. The historical pattern is a strong default rationale, and section 9 shows how to reuse it without retyping it, but it is still a rationale that has to be recorded against the element.
An empty cell is not whitespace. It is a claim: this threat does not apply here. Claims require rationale.

2. “Not applicable” is a finding, not a skip
The Playbook makes this point directly and almost in passing: when a threat does not exist for an element, it may be helpful to document why it does not apply.
That sentence is the highest-value habit in the entire methodology, and almost nobody does it.
Consider what a reviewer sees when a cell is blank. They cannot distinguish between:
- We analyzed Denial of Service against this data flow and determined it does not apply: the flow is a one-time configuration load at manufacturing, and no clinical function depends on its availability.
- We ran out of time on Thursday.
These two states are structurally identical in every threat model that has ever been handed to an assessor. One represents completed engineering work. The other represents a gap. If your document cannot tell them apart, then neither can the reviewer, and the rational reviewer response is to assume the second.
The rule to adopt: every cell in the matrix carries an explicit status. There are exactly three legitimate statuses, and they must be distinguishable in the artifact. Only the first two are a disposition; the third is the absence of one, made visible:
| Status | Meaning | Evidence required |
|---|---|---|
| Analyzed | Threat enumerated and carried forward into risk analysis | Threat statement, traced to risk register |
| Dispositioned N/A | Considered and ruled out | Written rationale, non-empty, reviewed |
| Not yet addressed | Default; no disposition yet, work outstanding | Tracked as open work |
The failure mode you are engineering out is that Dispositioned N/A and Not yet addressed look the same. Make them different in the schema, not just in the reviewer’s imagination.
A useful consequence falls out of this immediately: coverage stops being a subjective judgment. Coverage is not “cells filled in.” Coverage is cells that are Analyzed or Dispositioned N/A, divided by total cells. That number is computable, it is reportable, and it is honest.
3. Repudiation on data stores: the ambiguity nobody writes about
The Playbook’s matrix carries a question mark, not a mark, for Repudiation against data stores. The reason given is that organizations disagree: some categorize repudiation threats against the data store itself, and others categorize them against the processes that manage the store.
This is not a defect in the methodology. It is an honest acknowledgment that threat categorization is a convention, and conventions have to be chosen.
The practitioner action is straightforward and almost never taken:
- Pick a convention.
- Write it down in the methodology section of the threat model, not in someone’s head.
- Apply it uniformly across every element in the model.
Inconsistent categorization is what makes threat model review miserable. A reviewer who finds repudiation against the data store on page 4 and against the managing process on page 9 has to reconstruct your reasoning before they can assess your coverage — and reconstructing reasoning is exactly the work you were supposed to have done for them.
4. The same problem, worse: data flow versus process
The categorization ambiguity is not limited to repudiation. The Playbook notes that spoofing is a common threat to external entities and processes, but that many organizations instead categorize the spoofing threat against the data flow involved, and its guidance amounts to: do what makes sense for the needs of your organization. It also observes that identified threats may not fit cleanly into only one STRIDE type, and that the important thing is to capture and record the threats rather than where they are categorized.
That guidance is correct for internal work and insufficient for regulated work. Your threat model will be read by someone who did not build it — an assessor, a reviewer at a customer, a colleague who inherits the product in three years.
So the selection criterion is not which convention is fastest to author. It is which convention survives handoff. For threats that manifest in transit — tampering with a message, disclosure of data on the wire, flooding a link — categorizing against the data flow tends to read more clearly to an outside reader, because it names the thing the attacker actually touches. For threats that manifest in identity or authority, categorizing against the process or entity being tricked reads better.
5. External entities are scope boundaries wearing element costumes
The Playbook observes that organizations may protect their systems from interactions with external entities by threat modeling the spoof and repudiate threats, while modeling of other threats against those entities may be difficult and outside the scope of threat modeling activities.
This is worth dwelling on, because it is the cleanest statement in the literature of something practitioners do instinctively and document badly. You cannot apply tampering controls to a clinician. You cannot patch a hospital IT department. An external entity in your DFD is, functionally, the edge of your control — the matrix’s thin coverage of external entities is a statement about authority, not about risk.
The article-worthy point: say so explicitly. A threat model that silently stops at the trust boundary looks like an omission. A threat model that states “threats against external entity X beyond spoofing and repudiation are outside the scope of this analysis because the entity is not under the manufacturer’s design control; residual risk is addressed through [interface assumptions, security architecture documentation, customer security documentation]” looks like engineering.
Same stopping point. Completely different reception.
6. Trust boundary crossings as a defensible prioritization order
The Playbook’s worked example prioritizes threats that cross trust boundaries. This is worth adopting not only because it is good security practice, but because it gives you a defensible sequencing story when the analysis is time-boxed — which it almost always is.
“We started with the highest-value elements” is an opinion. “We enumerated threats in order of trust boundary crossings, completing all boundary-crossing flows before internal ones, and the remaining elements are tracked as open work with Not yet addressed status” is a plan with a documented ordering principle. If a schedule cuts your analysis short, the second sentence tells the reviewer exactly what you have and exactly what you do not.
Prioritization is not a substitute for coverage. It is a statement about the order in which coverage is achieved, which is why it only works if the uncovered remainder is explicitly tracked. See section 2.
7. Completion criteria: how do you know when you are done?
Methodologies rarely tell you when to stop. The Playbook offers something close to an exit condition: if you are working through the matrix and finding it difficult to identify new threats, that may indicate the activity is complete.
That is a saturation criterion, and it is more useful than it sounds, because it is observable. But by itself it is soft, so pair it with the structural criterion from section 2:
The threat identification activity is complete when every cell of the matrix carries a disposition, and continued analysis of the model is not producing new threats.
The first clause is objective and auditable. The second is a judgment call. You need both — the first alone would let you close out a model full of thin, box-checking entries, and the second alone gives a reviewer nothing to check.
8. Symmetric flows generate duplicate threats
This is not in the Playbook; it is a practitioner observation, and it will bite you the first time you model a real clinical system.
Bidirectional communication — a modality talking to a PACS, a pump talking to a server, any request/response protocol — is commonly drawn as two opposing data flows. STRIDE-per-Element then dutifully generates a full threat set against each arrow. You now have two tampering threats, two information disclosure threats, and two denial of service threats describing one interaction, with nearly identical text and nearly identical controls.
The consequences are not cosmetic:
- Reviewers read the duplication as padding, which erodes trust in the whole model.
- Risk registers inherit the duplicates, inflating counts and distorting any metric derived from them.
- Controls get written twice and maintained once, so they drift.
The fix is to model the interaction as the unit of analysis rather than the directional arrow, and to enumerate threats against the interaction. Direction still matters for some threats — asymmetric authentication is real — but it belongs as a property of the threat, not as a duplicated element.
9. The matrix is a generator, not an inventory
Four element types by six threat categories is manageable. A real system DFD with forty elements is not: the matrix is a combinatorial generator, and it will happily hand you several hundred candidate threats. Teams respond by either drowning or, more commonly, quietly abandoning systematic coverage around element fifteen.
Treat the matrix output as the input to an analysis step, not as the analysis:
- Generate the full candidate set. Do not prune during generation — pruning during generation is how coverage becomes unverifiable. (Modeling a bidirectional exchange as one interaction, per section 8, is a decision about what the elements are, made in the DFD before generation starts. It is not pruning of generated candidates.)
- Disposition each candidate: analyzed, or N/A with rationale (section 2). Anything not yet dispositioned stays visibly Not yet addressed; it does not disappear.
- Deduplicate and merge structurally identical threats across similar elements, preserving the element references so the merge is reversible.
- Promote the surviving threats into the risk register with traceability back to the generating cell.
Step 4 is the one that matters for regulated work. If a threat cannot be traced from register entry back to the matrix cell that produced it, then the matrix was a brainstorming aid, not a coverage argument — and coverage was the reason you used it.
A note on reusable rationale: the same N/A justification will legitimately recur across many elements of the same type. Let it be a named, reusable justification with per-cell override, rather than requiring fresh prose every time. If you force authors to retype rationale hundreds of times, they will paste whatever makes the field validate, and you will have traded a visible gap for a dishonest sentence.
10. Threat modeling is design input, not a security artifact in a folder
The last point connects this series back to Part 2: Writing Good Requirements for Medical Devices.
A threat model that terminates in a list of threats has not finished its job. The threats become risks, the risks get risk control measures, and — the step that teams routinely truncate - the risk control measures introduce new risks that must themselves be analyzed. An authentication control creates a lockout condition. A logging control creates a data disclosure surface and a storage exhaustion path. An integrity check creates a failure mode when it cannot reach its verification source.
That loop is not optional in a safety-regulated context, and it is the reason threat modeling cannot live in a separate security document maintained by a separate team on a separate cadence. The output of the threat model is design input. If it is not flowing into requirements, architecture, and the risk management file, it is documentation of an activity rather than an input to a design.
What to take away
- Treat the matrix as a coverage contract. Its value is auditable absence.
- Give every cell a disposition. “Considered and excluded, because X” is engineering work; a blank cell is indistinguishable from an oversight.
- Choose and document your categorization conventions — especially repudiation against data stores, and transit threats against flows versus processes.
- State your scope boundary at external entities explicitly rather than stopping silently.
- Prioritize by trust boundary crossings, and track the uncovered remainder.
- Define a completion criterion with both a structural and a saturation clause.
- Model bidirectional communication as one interaction, not two arrows.
- Generate broadly, disposition completely, deduplicate deliberately, trace everything into the risk register.
- Close the loop from risk control measures back into new risks.
Closing point. Every threat model presents the threats it found. Very few present evidence about the threats it did not find. That evidence is what a reviewer is actually looking for, and the matrix is the only structure in common use that can produce it — but only if you stop treating empty cells as nothing and start treating them as claims.
Appendix: Typical STRIDE Rationales
Section 9 argues that N/A rationale should be a named, reusable justification with per-cell override rather than fresh prose for every cell. What follows is the default set Highland uses as the starting point for that library: for each element type, whether each STRIDE category applies by default, and the one-line reason. Every entry is a default. The N/A entries are the rationale a cell inherits when nothing about the specific element argues otherwise; the “applies” entries are the reason a cell starts in Not yet addressed rather than Dispositioned N/A. Either can be overridden per element, and the override is what the reviewer should see.
Two of these entries take a position on the conventions discussed in sections 3 and 4. Repudiation against data stores is recorded as applying, which is the “against the store” convention. Spoofing against data flows is recorded as not applying, which places identity threats on the endpoints. If your methodology section chooses differently, change these two rows and keep the rest.
External Entity
| Category | Default | Rationale |
|---|---|---|
| Spoofing | Applies | External actors (users, third-party systems) are the classic spoofing target, impersonated via stolen credentials, forged tokens, or session hijacking. |
| Tampering | N/A | The entity is outside your trust boundary. Tampering attacks target systems and data you actually own. |
| Repudiation | Applies | Actors can deny having initiated requests. Non-repudiation (signed events, authentication logs, audit trails) is the defense. |
| Information Disclosure | N/A | Entities are sources of interaction, not objects of disclosure. Analyze disclosure where your system stores, transmits, or processes data. |
| Denial of Service | N/A | You cannot defend an external actor from denial of service. That is outside your trust boundary. |
| Elevation of Privilege | N/A | External entities hold no privileges inside your system to elevate. Privilege escalation is analyzed where privileges exist, in processes. |
Process
| Category | Default | Rationale |
|---|---|---|
| Spoofing | Applies | Processes run under a principal identity that can be impersonated via stolen credentials, forged tokens, or weak authentication. |
| Tampering | Applies | Process memory, code, configuration, or inputs can be modified by an attacker with access. Integrity checks and input validation are critical. |
| Repudiation | Applies | Processes act on behalf of users. Without non-repudiation controls (signed audit logs, secure logging), actions can be denied later. |
| Information Disclosure | Applies | Processes handle sensitive data in memory, logs, and error messages that can leak via verbose errors, debug endpoints, or side channels. |
| Denial of Service | Applies | Processes consume CPU, memory, file descriptors, and threads. They can be crashed, exhausted, or deadlocked. |
| Elevation of Privilege | Applies | Processes hold privileges that can be escalated via injection, unsafe deserialization, missing authorization checks, or sandbox escapes. |
Data Store
| Category | Default | Rationale |
|---|---|---|
| Spoofing | N/A | A store does not authenticate as a principal itself. Spoofing targets the actors or services accessing it. |
| Tampering | Applies | Stored data can be altered by unauthorized writes. Integrity controls, access control, and WORM or append-only designs mitigate. |
| Repudiation | Applies (convention) | Audit logs and records live in stores. If the store is mutable or lacks tamper-evidence, actions can be repudiated after the fact. |
| Information Disclosure | Applies | Stored data (PHI, secrets, records) is a prime exfiltration target. Encryption at rest and least-privilege access are the defenses. |
| Denial of Service | Applies | Storage can be filled, corrupted, or locked (ransomware, disk exhaustion, lock contention) to deny access to data. |
| Elevation of Privilege | N/A | A passive store holds no runtime privileges to escalate. Elevation is analyzed at the processes that read and write it. |
Data Flow
| Category | Default | Rationale |
|---|---|---|
| Spoofing | N/A (convention) | A data flow has no identity to spoof. Spoofing applies to the endpoints (sender and receiver), not the channel. |
| Tampering | Applies | In-transit data can be modified by an on-path attacker without integrity protection (HMAC, TLS, signed messages). |
| Repudiation | N/A | A flow does not act. Repudiation concerns actors disputing actions, which applies to processes and entities. |
| Information Disclosure | Applies | In-transit data can be read by an eavesdropper without encryption (TLS, message-level cryptography). |
| Denial of Service | Applies | Network flows can be flooded, dropped, or throttled to deny service. Rate limits, backpressure, and redundancy help. |
| Elevation of Privilege | N/A | A data flow has no privileges. There is nothing to elevate. |
Read against the matrix in section 1, this table reproduces the Playbook’s marks with two deliberate choices made where the Playbook leaves them open. That is the point: the grid tells you where the historical pattern is, and the rationale library tells the reviewer what you decided and why.
Sources: the STRIDE-per-Element characterizations, the external entity scope discussion, the repudiation-on-data-stores convention question, the categorization flexibility guidance, the trust boundary prioritization example, and the saturation-based completion criterion are drawn from the MDIC/MITRE Playbook for Threat Modeling Medical Devices (2021), pages 21-22. The symmetric flow duplication problem, the three-status cell model, the coverage computation, and the scaling and traceability guidance are practitioner observations from Highland Biomedical review experience and are not drawn from the Playbook.