Sample threat model — STRIDE, LLM-backed returns API
Executive summary
The Acme Returns API fronts an LLM-backed support agent that answers return questions, looks up orders, and — within limits — issues refunds. A STRIDE walk over its data-flow diagram produced 9 threats across four trust boundaries. Two stand out: prompt injection through the customer channel (TM-03) and the agent calling the refund tool beyond its intended scope (TM-08) — together they turn a support conversation into an unaudited financial action. First moves: deny-by-default per-tool RBAC with human approval on refunds, guardrail isolation of privileged instructions, and per-request context isolation so one tenant's PII never reaches another's session.
6 of 9 register rows carry citations; the linked ones were fetched live from the gateway's corpora during the run. Two rows (TM-05, TM-07) matched no source row and ship as marked analyst drafts; one row (TM-06) lists candidate provisions but its regulatory basis is unresolved. None of the three is papered over.
System & trust boundaries
Acme Returns AB (fictional) runs a customer-support returns flow: a public chat channel where an LLM agent handles return requests end-to-end. Components: the returns API edge (authentication, session handling), the LLM support agent (system instructions plus per-request retrieved context), two tools the agent can call (order lookup and refund), and a multi-tenant customer & order store holding PII.
Show the text form
[Customer / attacker]
| chat + REST over HTTPS <- B1: internet -> edge
[Returns API edge] (OAuth 2.0 access token, session)
| prompt assembly <- B2: untrusted input -> model context
[LLM support agent] (system instructions + customer message + retrieved context)
| tool calls <- B3: model output -> privileged action
[Order lookup] ---- [Refund tool] (financial action)
| queries <- B4: tenant isolation
[(Customer & order store -- multi-tenant, PII)]- B1Internet → API edge. Anonymous internet traffic meets the authenticated API surface (OAuth 2.0 tokens, sessions).
- B2Untrusted input → model context. Customer text is assembled into the same context window as privileged system instructions.
- B3Model output → privileged action. Agent output selects and parameterises tool calls — including the refund tool, a financial action.
- B4Tenant isolation. Retrieval crosses into a multi-tenant store holding PII and order history.
Threat register
One row per threat, walked per element and boundary. Severity and likelihood are analyst-assigned and would be confirmed or corrected in senior review.
| ID | STRIDE | Threat & boundary | Severity | Mitigation | Citations | Regulation | Status |
|---|---|---|---|---|---|---|---|
| TM-01 | Spoofing | Stolen or replayed OAuth access token impersonates a customer at the API edge B1 | High (Possible) | Short-lived, sender-bound access tokens; encrypted token storage; monitor for compromised service accounts | STRIDE-API-OAUTH-001 | — | cited |
| TM-02 | Spoofing | Session credential forged or predicted via a weak random number generator; account takeover B1 | High (Possible) | CSPRNG-backed session identifiers; new session token on authentication (ASVS V3.2.1); randomness verified per WSTG | STRIDE-CRYPTO-RANDOM-001 · CAPEC-196 · OWASP ASVS V3.2.1 · OWASP WSTG 4.2 — session mgmt schema | — | cited |
| TM-03 | Tampering | Prompt injection via customer message overrides system instructions B2 | High (Likely) | Input/output guardrail + privileged-instruction isolation | OWASP LLM01 · CWE-77 | EU AI Act Art. 15 | cited |
| TM-04 | Tampering | Returns-flow step skipping: the final refund-confirmation request is submitted directly, bypassing the eligibility checks of earlier steps B1 → B3 | Medium (Possible) | Server-side state machine over the returns flow; every stage transition validated server-side | CAPEC-140 | — | cited |
| TM-05 | Repudiation | A refund issued through the agent cannot later be attributed to a specific customer instruction and agent decision B3 | Medium (Possible) | Tamper-evident audit log of prompt, tool call, parameters, and approval — retained per policy | — | — | analyst draft — no fetched source; held for senior review |
| TM-06 | Information disclosure | Context-window leakage exposes another tenant's PII B2 / B4 | High (Possible) | Per-request context isolation + retrieval scoping | CWE-200 | NIS2 Art. 21 / GDPR Art. 32 (candidates) | flagged — regulatory_basis_unresolved |
| TM-07 | Denial of service | Unbounded chat traffic drives model-call spend and saturates the returns queue — no per-client budget B1 / B2 | Medium (Likely) | Per-client rate limits; token budgets; queue backpressure | — | — | analyst draft — no fetched source; held for senior review |
| TM-08 | Elevation of privilege | Agent calls the refund tool beyond intended scope (tool-permission escalation) B3 | Critical (Possible) | Per-tool RBAC, deny-by-default + human-in-loop on financial actions | ATT&CK T1548 · CWE-269 | DORA Art. 6 | cited |
| TM-09 | Elevation of privilege | Authentication bypass on the internal tool API reaches the refund endpoint without passing the agent's controls B3 | High (Possible) | Authenticate every internal hop; step-up authentication before privilege-changing actions (see §4, IAC-16.3) | CAPEC-115 | — | cited |
Linked citations are rows the gateway returned during this run, with source URL, publisher, and license preserved. Unlinked identifiers (OWASP LLM01, CWE-77, ATT&CK T1548, CWE-269, CWE-200 and the regulation references) carry over from the previously published sample register for this system. Rows with no matching source say so instead of carrying an invented reference.
Control mapping
Register rows mapped to controls from the gateway's security-controls catalog. Fragments are quoted as fetched.
| Control | Maps to | Fetched description |
|---|---|---|
| AAT-29.2 — Agent least-privilege scoping | TM-08 | “Confines each agent to the minimum permissions, assets, services, and network reach…” |
| IAC-16.3 — Step-up authentication for privilege changes | TM-08, TM-09 | “Asking to alter a privilege level triggers an extra authentication check before…” |
| IAC-20 — Least-privilege logical access | TM-08, TM-09 | “…each task needs, keeping every grant aligned with the least-privilege principle.” |
| IAC-21 — Least privilege for processes | TM-01 | “Access is held to the minimum required, permitting only the processes needed…” |
Product-security duties (CRA)
If the returns agent ships to customers as a product with digital elements — for example as an embeddable support widget — the Cyber Resilience Act's essential cybersecurity requirements attach to it. The gateway returned the operative annex:
Cyber Resilience Act, Annex I — Reg (EU) 2024/2847 — “ESSENTIAL CYBERSECURITY REQUIREMENTS — Part I Cybersecurity requirements relating to the properties of products with digital elements” (Publications Office of the European Union).
In a paid engagement each register row is mapped to the specific Annex I point it engages. This sample stops at the annex level: the fetched excerpt covers the Part I heading, not the itemised list, and we don't cite deeper than what was fetched. Applicability is a scoping input, not a conclusion — whether Acme's deployment is a product placed on the market, rather than a pure service, decides if the CRA attaches at all. A real engagement records that determination; here it is marked open.
Method note
- STRIDE over the DFD. All six categories walked per element and boundary of the §2 diagram; classic categories extended for the LLM surface — Tampering to prompt injection, Elevation of privilege to tool-permission escalation, Information disclosure to context-window leakage.
- Sources fetched through the Ansvar gateway. The STRIDE pattern library, CAPEC, OWASP (ASVS 4.0.3, WSTG 4.2), the security-controls catalog, and the Cyber Resilience Act text — every linked citation is a row the gateway returned during the run, with source URL, publisher, and license preserved. Nothing is cited from model recall.
- Refusal discipline. No fetched source → the row says so (TM-05, TM-07). Regulatory basis not confirmable at article level → the row is flagged
regulatory_basis_unresolved(TM-06). Gaps are marked, never filled with plausible text. - What a paid engagement adds. Your real architecture and a scoping call; enrichment across ATT&CK, CWE, and your sector's regulations; and a named senior reviewer who confirms or corrects every row before it ships.
Sign-off
Senior review: [shown for format — fictional sample, nothing to certify] Reviewer: [named reviewer — OSCP / CISSP / AI red team] Date: [—]
A paid engagement ships only after the named reviewer has validated every row and signed here. This sample is published unsigned, on purpose, so you can read the document exactly as it leaves the engine.
Want this for a real system? Scope a threat model →