How to run the chain
- Paste the shared rules once, or use each step as a standalone copy block (rules are inlined).
- Attach or paste the diagram. Set
{{representation_kind}}to image, mermaid, or svg. - Pick a role: experienced-threat-modeler, application-security, llm-caller. Default is experienced-threat-modeler.
- Copy one block at a time. The copied text starts with a
[chain]line that names this step and the next. The strip below this list remembers the last Copy click. - Run Track A in order from P-norm through P-report. After P-sol, run P-adv and P-controls before STRIDE. After P-qa, run P-report.
- Optionally run Track B (P-srf-join, P-srf-layer, P-srf-owner) with an operating model.
- After the track you used, run P-export-md then P-export-json. Save the first reply as a
.mdfile and the second as a.jsonfile. - Do not rephrase Shostack's four questions. Do not put mitigations in P-phantom.
On this page
Last copied: none. Next: P-norm (Normalize representation).
Shostack's Four Questions
- What are we working on?
- What can go wrong?
- What are we going to do about it?
- Did we do a good job?
Wording is from the Four Question Framework (CC-BY). Use those four sentences as written. State the team view and what we are working on right now.
PHANTOM-B questions (LLM subset)
- P Prompt injection: How could someone prompt inject (direct, indirect, multi-stage) through this component?
- H Hallucination: What if hallucinations exceed our hopes in this use of the component?
- A Anthropomorphization: Are we anthropomorphizing this component (treating a token generator as if it had intent, guilt, or a model of user versus attacker)?
- N Non-explainability: When must we explain or justify this component's output, and to whom? The model's own story is not an explanation.
- T Training issues: What if training data is bad by accident or on purpose, and how does that show up at this call site?
- O Over-reliance: What decisions does this LLM make, what control does it have, and does that expand the attack surface?
- M Missing security engineering: Did we skip the rest of security engineering and the SDL around this LLM (authn, authz, logging, isolation, least privilege)?
- B Biases: What biases does this model carry into this use case, and are they acceptable here?
Ask these eight questions for each chatbot or model-runtime node. STRIDE still applies to every component. Write mitigations in P-act.
Roles
- Experienced threat modeler (experienced-threat-modeler). Enumerate concrete scenarios a builder could act on this sprint. Prefer data-flow and trust-boundary analysis over catalogs. When a STRIDE letter does not apply to an element, say so and give a reason.
- Application security (application-security). Focus on entry points, authn/authz, input mediation, session handling, and control points the application team can change. Keep a provider-owned infrastructure threat in scope only when the diagram shows it and the application team must demand evidence.
- LLM caller (llm-caller). Focus on prompt construction, tool and retrieval inputs, over-reliance, and what the model is allowed to decide. Do not assume you can retrain the base model.
Sources
- Adam Shostack, The Four Question Framework for Threat Modeling (CC-BY).
- Adam Shostack, PHANTOM-B: A STRIDE Analog for LLMs (CC-BY).
- Crossman et al., Auspex (arXiv:2503.09586). Two-stage chain, cumulative prompt fill, threat matrix, SME evaluation. The prompts here are rebuilt from the paper's published figures. JPMC's withheld tradecraft text is not in this pack.
- IETF RFC 6819. Attack assumptions and existing features are stated before new threats. Do not copy its OAuth threat list onto an unrelated diagram.
- CoSAI SRF accountability data: threats.json, personas.json, matrix.json.
Lane
Track A elicits threats from the diagram and classifies them. Track B writes one SRF persona and one party onto each threat. If matrix.json says shared, still name one lead. Cite an OWASP, ATLAS, or AI Exchange id only when it exists in that source. After either track, the export pair writes the files a reviewer can keep: a markdown report and the completed JSON.
Q1. What are we working on?
Read the diagram into a solution description. Then state attackers and existing controls. Each step is filled with the prior JSON.
[chain] This prompt is P-norm (Normalize representation). Next prompt: P-diag (Decompose diagram). Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
Shostack question: What are we working on?
Step: P-norm. Normalize the system representation into a canonical inventory.
Representation kind: {{representation_kind}}
Representation follows this line. If kind is mermaid, parse the source text first (nodes, edges, subgraphs as candidate trust zones). If kind is svg, parse groups, labels, and connectors; do not rely on vision alone. If kind is image, read the image only.
{{representation}}
Return a JSON object with this shape:
{
"system_name": "string",
"perspective": "string naming team view and what we are working on right now",
"representation": { "kind": "image|mermaid|svg", "source_id": "filename or unknown", "version": "drawn or labeled version, or unknown", "commit": "commit if labeled, or unknown" },
"inventory": {
"components": [{"id": "kebab-id", "name": "", "type": "process"}],
"external_actors": [{"id": "", "name": "", "type": "actor"}],
"data_stores": [{"id": "", "name": "", "type": "store"}],
"data_flows": [{"id": "", "from": "id", "to": "id", "label": "", "crosses_boundary": "boundary-id or null"}],
"trust_boundaries": [{"id": "", "name": "", "contains": ["id"]}],
"llm_components": [],
"missing_trust_boundaries": false
}
}
Id rules: lowercase kebab-case, derived from the label on the diagram. Reuse the same id if the label is the same. Do not merge distinct boxes. llm_components may be empty at this step.
[chain] This prompt is P-diag (Decompose diagram). Next prompt: P-app (Application details). Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
Shostack question: What are we working on?
Step: P-diag. Write a long-form architecture description of the system in the diagram.
Inventory from P-norm:
{{inventory}}
Original representation (kind={{representation_kind}}):
{{representation}}
Write architecture_description that covers:
- every component and how it relates to the others
- system entry points
- data flow
- security boundaries (drawn ones only)
- public vs private resources
- system availability or fault-tolerance properties only if the diagram shows them
- external dependencies
- storage and data security properties only if the diagram shows them
Return JSON:
{
"architecture_description": "prose",
"inventory": <echo the inventory; correct ids only if the diagram contradicts P-norm, and list corrections in a "corrections" array>
}
[chain] This prompt is P-app (Application details). Next prompt: P-feat (Key features). Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
Shostack question: What are we working on?
Step: P-app. Condense the architecture description into application details.
Architecture description:
{{architecture_description}}
Return JSON:
{
"application_details": "short prose: function, actors, data the system handles, and the team perspective"
}
[chain] This prompt is P-feat (Key features). Next prompt: P-scope (In-scope components). Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
Shostack question: What are we working on?
Step: P-feat. List key features that matter more for threat modeling than the rest of the architecture.
Architecture description:
{{architecture_description}}
Application details:
{{application_details}}
Return JSON:
{
"key_features": ["each item names a diagram element and why it changes the threat surface"]
}
[chain] This prompt is P-scope (In-scope components). Next prompt: P-sol (Solution description). Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
Shostack question: What are we working on?
Step: P-scope. Mark which architectural components must be included in threat modeling.
Perspective remains what we are working on right now. Do not pull in an unshown enterprise.
Architecture description:
{{architecture_description}}
Application details:
{{application_details}}
Key features:
{{key_features}}
Inventory:
{{inventory}}
Return JSON:
{
"in_scope": [{"id": "inventory-id", "rationale": "why this must be modeled"}],
"out_of_scope": [{"id": "inventory-id", "rationale": "why this stays out for this perspective"}]
}
[chain] This prompt is P-sol (Solution description). Next prompt: P-adv (Attacker capabilities and claim boundary). Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
Shostack question: What are we working on?
Step: P-sol. Combine prior Q1 outputs into a solution description (solS) plus a structured DFD.
Architecture description:
{{architecture_description}}
Application details:
{{application_details}}
Key features:
{{key_features}}
In scope:
{{in_scope}}
Out of scope:
{{out_of_scope}}
Inventory:
{{inventory}}
Return JSON:
{
"solution_description": "prose of how the architecture functions as a whole",
"inventory": <canonical inventory for all later steps>,
"in_scope": [...],
"out_of_scope": [...]
}
[chain] This prompt is P-adv (Attacker capabilities and claim boundary). Next prompt: P-controls (Existing security features). Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
Shostack question: What are we working on?
Step: P-adv. State attacker capabilities and the claim boundary before eliciting threats. This is the RFC 6819 §2.2 shape: assumptions first, then positions. Do not copy OAuth threats.
Inventory:
{{inventory}}
In scope:
{{in_scope}}
Out of scope:
{{out_of_scope}}
Solution description:
{{solution_description}}
Write adversary.assumptions as capabilities someone already has (network position, credentials, ability to send prompts, physical access). Do not invent an attacker who can already do everything.
Write adversary.positions: one row per drawn trust boundary or in-scope zone. Each row needs id, zone (boundary or component id), actor (who is there), and already_can (what they can do from that zone without a new exploit).
Write claim_boundary.does_not_claim: attacks this review will not treat as in play. Tie each item to a reason from the diagram or the named perspective (for example a global passive observer if the diagram is one application, or physical theft of a provider datacenter that is not drawn).
Write claim_boundary.box: the time, access, or component limit of this review (what we are working on right now).
Return JSON:
{
"adversary": {
"assumptions": ["..."],
"positions": [{"id": "pos-internet", "zone": "internet", "actor": "unauthenticated user", "already_can": "send HTTP to the drawn entry point"}]
},
"claim_boundary": {
"does_not_claim": ["..."],
"box": "..."
}
}
[chain] This prompt is P-controls (Existing security features). Next prompt: P-llm-cut (Mark the LLM subset). Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
Shostack question: What are we working on?
Step: P-controls. List security features already visible on the diagram, before writing new threats. This is the RFC 6819 §3 shape: existing features first. Do not invent a control that is not drawn or named.
Solution description:
{{solution_description}}
Inventory:
{{inventory}}
Adversary:
{{adversary}}
Include authn, TLS, filters, isolation, logging, human approval, network policy, or identity providers only if a label, component, or flow shows them. If none are drawn, return an empty array and set none_drawn true.
Return JSON:
{
"existing_controls": [{"id": "ctl-...", "name": "", "diagram_referent": "inventory id", "kind": "authn|tls|filter|isolation|logging|approval|network|identity|other"}],
"none_drawn": false
}
[chain] This prompt is P-llm-cut (Mark the LLM subset). Next prompt: P-stride (STRIDE elicitation). Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
Shostack question: What are we working on?
Step: P-llm-cut. Mark which nodes receive PHANTOM-B. Per Shostack, PHANTOM-B applies to the front end and model runtime, not every box.
Solution description:
{{solution_description}}
Inventory:
{{inventory}}
Include a node if it: assembles or receives prompts, hosts a chatbot, or runs or calls an LLM.
Exclude a node if it only stores weights, serves as a generic database, or is a third-party hub that is not executing inference in this diagram.
Return JSON:
{
"llm_subset": ["component-id", "..."],
"llm_subset_rationale": [{"id": "", "include": true, "reason": ""}]
}
Q2. What can go wrong?
STRIDE on in-scope elements and crossing flows. PHANTOM-B on the LLM subset. Then merge.
[chain] This prompt is P-stride (STRIDE elicitation). Next prompt: P-phantom (PHANTOM-B elicitation). Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
{{role_tradecraft}}
Cyber role: {{cyber_role}}
Shostack question: What can go wrong?
Step: P-stride. Apply STRIDE to every in-scope element and every data flow that crosses a trust boundary.
STRIDE letters: S spoofing, T tampering, R repudiation, I information disclosure, D denial of service, E elevation of privilege.
For each applicable letter, write one concrete scenario that can happen in this system. If a letter does not apply, record not_applicable with a reason. Do not skip a letter in silence.
Each scenario row must set attacker_position to an id from adversary.positions. That position is who already sits in which zone and what they can already do. Do not invent a new position here.
Solution description:
{{solution_description}}
Inventory:
{{inventory}}
In scope:
{{in_scope}}
Adversary:
{{adversary}}
Existing controls:
{{existing_controls}}
Claim boundary:
{{claim_boundary}}
Return JSON:
{
"stride_considerations": [
{
"element_id": "component or flow id",
"letter": "S",
"status": "scenario|not_applicable",
"scenario": "concrete text or empty if not_applicable",
"reason": "required when not_applicable",
"diagram_referent": "element_id",
"preconditions": "visible in the diagram",
"attacker_position": "pos-id from adversary.positions",
"asset": "what is harmed"
}
]
}
[chain] This prompt is P-phantom (PHANTOM-B elicitation). Next prompt: P-dedup (Dedup and compose threat list). Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
{{role_tradecraft}}
Cyber role: {{cyber_role}}
Shostack question: What can go wrong?
Step: P-phantom. For each LLM or chatbot component, ask the PHANTOM-B questions about that node. Leave defenses, controls, and mitigations for P-act.
Ask, for each id in llm_subset:
1. P Prompt injection: How could someone prompt inject (direct, indirect, multi-stage) through this component?
2. H Hallucination: What if hallucinations exceed our hopes?
3. A Anthropomorphization: Are we anthropomorphizing?
4. N Non-explainability: When must we explain or justify the output, and to whom?
5. T Training issues: What if training data is bad by accident or on purpose?
6. O Over-reliance: What decisions is the LLM making, and does that expand the attack surface?
7. M Missing security engineering: Did we skip the rest of the SDL around this component?
8. B Biases: What biases does the model have, and are they acceptable in this use case?
Each scenario row must set attacker_position to an id from adversary.positions.
Solution description:
{{solution_description}}
Inventory:
{{inventory}}
LLM subset:
{{llm_subset}}
Adversary:
{{adversary}}
Existing controls:
{{existing_controls}}
Return JSON:
{
"phantom_considerations": [
{
"element_id": "llm component id",
"letter": "P",
"status": "scenario|not_applicable",
"scenario": "concrete instance in this system, or empty",
"reason": "required when not_applicable",
"diagram_referent": "element_id",
"preconditions": "",
"attacker_position": "pos-id from adversary.positions",
"asset": ""
}
]
}
[chain] This prompt is P-dedup (Dedup and compose threat list). Next prompt: P-cia (CIA mapping). Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
Shostack question: What can go wrong?
Step: P-dedup. Merge STRIDE and PHANTOM-B scenarios into threat list TSS.
Perspective:
{{perspective}}
Inventory:
{{inventory}}
Adversary:
{{adversary}}
STRIDE considerations:
{{stride_scenarios}}
PHANTOM-B considerations:
{{phantom_scenarios}}
Rules:
- Drop not_applicable rows.
- Merge two scenarios that name the same failure on the same referent into one threat. Record source as "both" when both methods found it.
- Keep a compositional threat only if the named perspective can change a control point on this diagram.
- Assign ids T1, T2, ... in diagram order (entry points first).
- Copy attacker_position from the source row. It must be an adversary.positions id.
- stride, phantom_b, cia, and action may be empty arrays / stub objects; later steps fill them. Include a stub action of type accept and detail "pending P-act" if required by schema.
Return JSON:
{
"threats": [
{
"id": "T1",
"scenario": "actor or failure, referent, preconditions, asset, why it can happen here",
"diagram_referent": "inventory id",
"preconditions": "",
"attacker_position": "pos-id",
"asset": "",
"source": "stride|phantom-b|both",
"stride": [],
"phantom_b": [],
"cia": [],
"action": { "type": "accept", "detail": "pending P-act" }
}
]
}
Q3. What are we going to do about it?
Map CIA, STRIDE, and PHANTOM-B letters. Then choose mitigate, eliminate, transfer, or accept in P-act, with a validation on mitigate and eliminate.
[chain] This prompt is P-cia (CIA mapping). Next prompt: P-stride-map (STRIDE mapping). Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
Shostack question: What are we going to do about it?
Step: P-cia. Map each threat scenario to CIA. Multi-label is allowed.
C Confidentiality, I Integrity, A Availability.
Solution description:
{{solution_description}}
Threats:
{{threats}}
Return the same threats array with cia filled. Do not add or drop threats. Do not fill action.
Return JSON:
{ "threats": [ ... ] }
[chain] This prompt is P-stride-map (STRIDE mapping). Next prompt: P-phantom-map (PHANTOM-B mapping). Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
Shostack question: What are we going to do about it?
Step: P-stride-map. Map each threat scenario to STRIDE letters. Multi-label is allowed.
Solution description:
{{solution_description}}
Threats:
{{threats}}
Return the same threats array with stride filled. Do not add or drop threats.
Return JSON:
{ "threats": [ ... ] }
[chain] This prompt is P-phantom-map (PHANTOM-B mapping). Next prompt: P-act (Choose an action). Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
Shostack question: What are we going to do about it?
Step: P-phantom-map. Attach PHANTOM-B letters only when the scenario was elicited from the LLM subset. Do not force every STRIDE threat into PHANTOM-B.
Letters: P prompt injection, H hallucination, A anthropomorphization, N non-explainability, T training issues, O over-reliance, M missing security engineering, B biases.
LLM subset:
{{llm_subset}}
Threats:
{{threats}}
Return the same threats array with phantom_b filled per the rule above.
Return JSON:
{ "threats": [ ... ] }
[chain] This prompt is P-act (Choose an action). Next prompt: P-qa (Self-check). Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
Shostack question: What are we going to do about it?
Step: P-act. Choose one action per threat: mitigate, eliminate, transfer, or accept.
Write the mitigate, eliminate, transfer, or accept choice here. Leave P-phantom without defenses.
- mitigate: make the attack harder at a named control point on the diagram.
- eliminate: remove the feature or interface that creates the threat.
- transfer: another party is better placed to handle it; name that party as shown on the diagram (customer, provider, or an external actor id).
- accept: keep the threat; say why the cost of the other options undermines the work.
Mitigation detail must name a control_point whose id exists in the inventory.
For mitigate or eliminate, set action.validation: kind is test, log, or fail_condition, and detail is something a reviewer could run or watch (a test name, a log line, or a fail condition on that control_point). Transfer and accept may set validation to null. Optional citations may include owasp_llm_top10 (form LLMnn:2025), ai_exchange_slug (one of the published slugs), or atlas (AML.T*). Omit any citation you cannot pin. Do not invent ids.
Solution description:
{{solution_description}}
Inventory:
{{inventory}}
Existing controls:
{{existing_controls}}
Threats:
{{threats}}
Return the same threats array with action, validation, and optional citations filled.
Return JSON:
{ "threats": [ ... ] }
Q4. Did we do a good job?
Mechanical self-check, then write the readable report. Leave the reviewer line empty.
[chain] This prompt is P-qa (Self-check). Next prompt: P-report (Write the readable report). Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
Shostack question: Did we do a good job?
Step: P-qa. Check the work before any human review.
Full threat matrix so far:
{{full_matrix}}
Check, and set each boolean false if the check fails:
1. inventory_components_in_solS: every inventory component id appears in solution_description.
2. boundary_crossings_covered: every trust boundary has at least one crossing-flow threat, or a gap explaining why not.
3. phantom_b_complete: every llm_subset id has all eight PHANTOM-B letters represented in phantom_considerations or in threats sourced from phantom-b. If you lack the consideration list, infer from threats and list remaining letters in gaps.
4. stride_considered: every in-scope process was considered for all six STRIDE letters (scenario or not_applicable). If unknown, set false and explain.
5. actions_complete: every threat has action.type in mitigate, eliminate, transfer, accept, and detail is not "pending P-act".
6. open_assumptions: list assumptions that are not on the diagram.
7. gaps: list failed checks in plain language.
8. adversary_stated: adversary.assumptions is non-empty and every in-scope trust boundary has a positions row, or a gap says which zone was skipped.
9. existing_controls_listed: existing_controls is present. Empty is allowed only when none_drawn is true.
10. claim_boundary_stated: claim_boundary.does_not_claim and claim_boundary.box are non-empty.
11. actions_have_validation: every mitigate or eliminate action has validation.kind in test, log, fail_condition and non-empty detail.
12. attacker_positions_bound: every threat.attacker_position is an id in adversary.positions.
Also confirm every threats[].diagram_referent exists in inventory (components, external_actors, data_stores, or data_flows). List misses in gaps.
Return the full matrix JSON with qa filled:
{
"system_name": "",
"perspective": "",
"representation": {},
"inventory": {},
"solution_description": "",
"llm_subset": [],
"threats": [],
"qa": {
"inventory_components_in_solS": true,
"boundary_crossings_covered": true,
"phantom_b_complete": true,
"stride_considered": true,
"actions_complete": true,
"adversary_stated": true,
"existing_controls_listed": true,
"claim_boundary_stated": true,
"actions_have_validation": true,
"report_present": false,
"open_assumptions": [],
"gaps": []
},
"adversary": {},
"existing_controls": [],
"claim_boundary": {}
}
[chain] This prompt is P-report (Write the readable report). Next prompt: P-export-md (Write the downloadable markdown report). Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
Shostack question: Did we do a good job?
Step: P-report. Write the readable threat model from the JSON. A reviewer must be able to read report.markdown without opening the rest of the object.
Full matrix:
{{full_matrix}}
report.markdown sections, in this order, as headings:
1. Title, date (today if unknown), method (Shostack Four Questions; STRIDE on in-scope elements; PHANTOM-B on llm_subset), role. Reviewer: leave blank.
2. System, representation.version / source_id, perspective, claim_boundary.box.
3. Attacker assumptions and positions.
4. Architecture (short), trust boundaries, in_scope and out_of_scope.
5. Existing controls. If none_drawn, say so.
6. Threats grouped by diagram_referent. Each: id, scenario, attacker_position, STRIDE / PHANTOM-B / CIA, action, validation.
7. What this model does not claim (claim_boundary.does_not_claim).
8. qa.gaps and open_assumptions.
9. Reviewer line with empty name and date fields.
Do not add threats. Do not drop threats. Set qa.report_present true.
Set chain_meta.method to the method sentence above, chain_meta.date to an ISO date, chain_meta.prompt_pack_version to 1.2, chain_meta.reviewer to null.
Return the full matrix JSON with report and chain_meta filled:
{
"system_name": "",
"perspective": "",
"representation": {},
"inventory": {},
"adversary": {},
"existing_controls": [],
"claim_boundary": {},
"solution_description": "",
"llm_subset": [],
"threats": [],
"qa": {},
"report": { "title": "", "markdown": "full document", "reviewer": null },
"chain_meta": { "prompt_pack_version": "1.2", "role": "{{cyber_role}}", "method": "", "date": "", "reviewer": null, "track_b_applied": false }
}
What Track A has filled
The assistant JSON after P-report is the Track A matrix. Optional
Track B is next. Then run the
export pair and save those two replies as files.
Schema:
eval/threat-model/schema.json.
Eval path: <system-id>/image.json (or
mermaid.json / svg.json).
inventory,solution_description,llm_subset.adversary: assumptions and positions (who already sits in which zone).existing_controls: only features drawn on the diagram.claim_boundary: what this review does not claim, plus the time or component box.threats: ids T1, T2, and so on. Each row hasscenario,diagram_referent,attacker_position, STRIDE letters, PHANTOM-B letters when the referent is an LLM node, CIA, oneaction, andvalidationon mitigate or eliminate.qaandreport.markdown. Leavereport.reviewerempty.
Track B is optional and reads the same JSON. After the track you used, run the export pair and save the two replies.
Track B (optional): SRF accountability
Off by default. Consumes the Track A JSON plus an operating model. Join published AI Exchange slugs from threats.json instead of re-deriving them.
[chain] This prompt is P-srf-join (Join AI Exchange slugs). Next prompt: P-srf-layer (Assign SRF layer). Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
Track B is optional. Off by default. This step assigns SRF accountability. It does not invent threats.
Step: P-srf-join. Fetch https://aisharedresponsibility.com/data/threats.json now. Use only ids that exist in that file.
Published slugs: directpromptinjection, indirectpromptinjection, evasion, runtimemodelpoison, devmodelpoison, datapoison, supplymodelpoison, disclosureinoutput, modelinversionandmembership, devdataleak, modelexfiltration, runtimemodelleak, devmodelleak, airesourceexhaustion, inputdataleak, outputcontainsconventionalinjection.
Operating model: {{operating_model}}
Full Track A matrix:
{{full_matrix}}
For each threat, if the scenario is the same failure as a slug, set:
srf.join.ai_exchange_slug = that slug
srf.join.copied_from_threats_json = true
srf.layer, srf.affected_layers, srf.persona, srf.party copied from threats.json accountability[{{operating_model}}]
If no slug matches, set srf.join.ai_exchange_slug to null and copied_from_threats_json to false. Leave layer/persona/party for P-srf-layer and P-srf-owner.
Do not invent slugs. Do not use "shared" as srf.party.
Return JSON:
{ "threats": [ ... with srf objects ... ], "operating_model": "{{operating_model}}" }
[chain] This prompt is P-srf-layer (Assign SRF layer). Next prompt: P-srf-owner (Assign one accountable persona). Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
Track B. Step: P-srf-layer. Assign the primary SRF layer where the control point lives, not where the harm appears.
Layers: L1 AI Business and Usage, L2 AI Information, L3 AI Application, L4 AI Platform, L5 AI Model Provider.
If srf.join.copied_from_threats_json is true, do not change srf.layer or srf.affected_layers.
Operating model: {{operating_model}}
Threats:
{{threats}}
Return JSON:
{ "threats": [ ... ] }
[chain] This prompt is P-srf-owner (Assign one accountable persona). Next prompt: P-export-md (Write the downloadable markdown report). Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
Track B. Step: P-srf-owner. Name one accountable persona and one party per threat.
Fetch now:
- https://aisharedresponsibility.com/data/personas.json
- https://aisharedresponsibility.com/data/matrix.json
Persona ids (cosai-core only unless the diagram is a federated consortium): agentic-platform-provider, application-developer, data-provider, ai-system-users, ai-system-governance, model-provider, ai-model-serving, ai-platform-provider.
Operating model: {{operating_model}}
Threats:
{{threats}}
Rules:
- Exactly one accountable persona per threat.
- srf.party is customer or provider. Never "shared". If matrix.json says shared at that layer, still name one lead and put the counterparty duty in srf.note.
- If srf.join.copied_from_threats_json is true, keep the copied persona and party.
- Persona must exist in personas.json.
Return the full matrix JSON with srf filled on every threat:
{
"system_name": "",
"perspective": "",
"representation": {},
"inventory": {},
"adversary": {},
"existing_controls": [],
"claim_boundary": {},
"solution_description": "",
"llm_subset": [],
"threats": [ ... ],
"qa": {},
"report": {},
"chain_meta": { "track_b_applied": true, "role": "{{cyber_role}}", "reviewer": null }
}
What Track B has filled
The assistant JSON after P-srf-owner is the Track A matrix with
srf on every threat. Same schema;
chain_meta.track_b_applied is true. Re-run the export pair
on this JSON so the markdown report includes layer, persona, and party.
srf.layer: L1 to L5, the layer where the control point lives.srf.persona: one id from personas.json.srf.party:customerorprovider. Nevershared.srf.join.ai_exchange_slug: a published slug from threats.json, or null.
Track B does not add threats. A threat with no matching slug still needs layer, persona, and party from P-srf-layer and P-srf-owner. Next, run Export the report and JSON on this JSON.
Export the report and JSON
These two prompts run after Track A, and again after Track B if you used it.
P-export-md writes the readable report; save that reply as a
.md file. P-export-json writes the completed record; save that
reply as a .json file. Leave the reviewer line empty.
[chain] This prompt is P-export-md (Write the downloadable markdown report). Next prompt: P-export-json (Write the completed JSON file). Do not echo this line in the markdown.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
This step writes the downloadable report. Output the markdown document only, starting at the title heading. Do not wrap it in a JSON object or in fences.
Step: P-export-md. Consume the completed matrix from Track A (after P-report) or Track B (after P-srf-owner). Write a report a reviewer can read without opening the JSON.
Full matrix:
{{full_matrix}}
Required document shape, in this order:
# Threat model: {system_name}
A metadata table with rows Date (ISO, today if unknown), Method (Shostack Four Questions; STRIDE on in-scope elements; PHANTOM-B on llm_subset), Role (from chain_meta.role), Representation (kind, source_id, version, commit; write unknown when the matrix says unknown), Perspective, Reviewer (empty cell).
## Claim boundary
One short paragraph from claim_boundary.box. Then a bullet list of claim_boundary.does_not_claim.
## Attacker
Assumptions as bullets from adversary.assumptions. Then a table of adversary.positions with columns Id, Zone or trust boundary, Capability.
## Architecture
A short paragraph from solution_description. Then ### Trust boundaries, ### In scope, and ### Out of scope. Use the inventory and scope arrays. If missing_trust_boundaries is true, say so under Trust boundaries.
## Existing controls
A table with columns Id, Feature, Diagram referent. If none_drawn is true and the list is empty, write one sentence that no security feature was drawn.
## Threats
One ### heading per diagram_referent, using that id as the heading text. Under each heading, a table with columns ID, Scenario, Attacker position, STRIDE, PHANTOM-B, CIA, Action, Validation. The Scenario cell is the full scenario sentence. Action is type plus detail. Validation is kind plus detail, or empty for transfer and accept. PHANTOM-B is empty when the referent is not in llm_subset.
If any threat has srf.persona or srf.layer, add columns Layer, Persona, Party after Validation.
## What this model does not claim
The claim_boundary.does_not_claim list again, as bullets.
## Open assumptions and gaps
Two short lists from qa.open_assumptions and qa.gaps. If a list is empty, write None recorded.
## Reviewer
Name:
Date:
Leave both blank.
Rules:
- Include every threat. Do not add threats.
- Do not invent components, vendors, networks, or trust boundaries.
- Do not fill the reviewer name or date.
- When srf is present, use the persona, layer, and party values from the matrix.
- Pipe tables must be valid GitHub-flavored markdown.
[chain] This prompt is P-export-json (Write the completed JSON file). Export ends here. Save the P-export-md reply as a .md file and this reply as a .json file. If Track B is not yet applied, optional next: P-srf-join (Join AI Exchange slugs). If Track B is already applied, stop. Do not echo this line in the JSON.
You are producing one step of a threat model for an AI system from a system representation (image, Mermaid, or SVG).
Rules:
- Use Shostack's Four Questions in this exact wording: What are we working on? What can go wrong? What are we going to do about it? Did we do a good job?
- Name the perspective: what we are working on right now, and which team view (application, platform, or model caller).
- Work only from the diagram and the prior chain output named in this prompt. Do not invent components, vendors, networks, or trust boundaries that are not drawn.
- If trust boundaries are missing from the diagram, set inventory.missing_trust_boundaries to true and record that as a finding. Do not invent boundaries silently.
- Every threat scenario must name a diagram_referent whose id exists in the inventory.
- Do not recite a generic catalog line (for example "LLMs can be prompt-injected") with no referent in this diagram.
- Do not use DREAD, OCTAVE, or attack trees as the primary method.
- PHANTOM-B is a set of questions for LLM and chatbot components. Do not force every STRIDE threat into a PHANTOM-B letter.
- Do not put mitigations, controls, or defenses in a PHANTOM-B elicitation step.
- Do not invent OWASP, ATLAS, or AI Exchange identifiers. Cite an id only if you are certain it exists; otherwise omit it.
- Output JSON only, matching the schema named in this prompt. No markdown fences, no commentary outside JSON.
- Once adversary.positions exists, every threat must set attacker_position to one of those ids.
- List an existing control only when a label, component, or flow on the diagram shows it.
- For mitigate or eliminate, action.validation is required: kind test, log, or fail_condition, plus detail a reviewer could run.
- Leave report.reviewer empty. A human fills it.
Step: P-export-json. Write the completed threat-model JSON file. Output JSON only. Pretty-print with two-space indent. No fences and no commentary outside the object.
Full matrix:
{{full_matrix}}
Keep every field already present. Do not add threats. Do not drop threats.
Required on the returned object:
- Matches the schema at the pack schema_url.
- inventory, adversary, existing_controls, claim_boundary, solution_description, llm_subset, threats, and qa stay complete.
- report.markdown is the full readable document with the same sections as P-export-md. If report.markdown is already complete, echo it. If a required section is missing, rewrite only that section from the matrix fields.
- report.title is Threat model: {system_name}.
- report.reviewer is null.
- qa.report_present is true.
- chain_meta.prompt_pack_version is 1.2.
- chain_meta.method names Shostack Four Questions, STRIDE on in-scope elements, and PHANTOM-B on llm_subset.
- chain_meta.date is an ISO date (today if unknown).
- chain_meta.reviewer is null.
- chain_meta.track_b_applied is true only when every threat has srf.persona and srf.party of customer or provider. Otherwise false.
- Every threat.attacker_position is an id in adversary.positions.
- Every mitigate or eliminate action has validation.kind in test, log, fail_condition.
- srf.party is never shared.
Return the full matrix JSON:
{
"system_name": "",
"perspective": "",
"representation": {},
"inventory": {},
"adversary": {},
"existing_controls": [],
"claim_boundary": {},
"solution_description": "",
"llm_subset": [],
"threats": [],
"qa": {},
"report": { "title": "", "markdown": "full document", "reviewer": null },
"chain_meta": { "prompt_pack_version": "1.2", "role": "{{cyber_role}}", "method": "", "date": "", "reviewer": null, "track_b_applied": false }
}
Evaluation baselines
P-zeroshot and P-identity are the two short baselines scored in
eval/threat-model/. Machine scores stay open until the SME sheets
in that directory are filled.
[chain] This prompt is P-zeroshot (Zero-shot threat model). This prompt is not in the default chain. Do not echo this line in the JSON.
Threat model this AI system diagram. Representation kind: {{representation_kind}}.
{{representation}}
Return JSON with system_name, perspective, inventory (components, external_actors, data_stores, data_flows, trust_boundaries, llm_components), solution_description, llm_subset, and threats. Each threat needs id, scenario, diagram_referent, stride, phantom_b, cia, and action (type mitigate|eliminate|transfer|accept, plus detail).
[chain] This prompt is P-identity (Short expert identity). This prompt is not in the default chain. Do not echo this line in the JSON.
You are an expert threat modeler. Using STRIDE, threat model the following AI system diagram (kind={{representation_kind}}).
{{representation}}
List threats with STRIDE type, impact, and a mitigation.
Output schema
Full JSON Schema: eval/threat-model/schema.json.
Gold diagrams (five systems, three formats) and the scoring scripts are in
eval/threat-model/ of the site repository.