Skip to main content

Use case — Threat modelling

Threat modelling has a predictable failure in fast-paced environments — either it is done too early (and is out of date by the time the code arrives), or it is done too late (and turns into compliance theatre). The MCP helps to do it at a useful moment: the agent extracts from the manual the threats already catalogued for the project's risk level and the system's concerns, and anchors them in the controls that mitigate them — with IDs.

The example here is a public user-management API (create account, authenticate, recover password). In two calls to the server, the agent gathers the material for a defensible threat model, with the confidence of each link marked in mitigation_confidence. Today, every served link is derived, structural. If another value appears, the link is inferred and is labelled as such.

Prior requirements​

  • MCP installed, skill loaded.
  • Project risk level — L2 in the example (public API, user data).

Flow​

1. Identify the system's concerns​

From the prose description, map to the ontological vocabulary:

System aspectConcern
Login / authenticationauth
Public REST endpointsapi
Input validation (email, password strength)validation
Password hashing, tokensencryption
Audit log of sensitive operationslogging

→ concerns = ["auth", "api", "validation", "encryption", "logging"]

2. Threat landscape​

Important: get_threat_landscape runs consult internally — do not call consult_security_requirements beforehand.

get_threat_landscape({
"risk_level": "L2",
"concerns": ["auth", "api", "validation", "encryption", "logging"]
})

Expected output (real shape — threats MT-NNN; each link cites the control_id):

{
"threats": [
{
"id": "MT-055", "name": "Interfaces expostas sem isolamento",
"chapter_id": "04-arquitetura-segura", "threat_category": "STRIDE",
"mitigation_confidence": "derived", "mitigation_strength": "parcial",
"mitigated_by": [
{"control_id": "CTRL-infrastructure-segmentacao-e-controlo-arquitetural-dceb3c1f0b", "domain": "infrastructure"}
]
}
]
}
Concern routing — routing_basis

The response declares, for each concern, the basis of the routing in routing_basis: domain_chapter when the concern has a threat chapter of its own, activated_controls when the threats arrive through the chapters that define the activated controls. Reading routing_basis before structuring the threat model tells where each threat came from — and, with that, how to present it.

3. Practices by role (optional, but useful)​

For the role that will mitigate (e.g.: arquitetos-software in design, developer in implement):

get_guide_by_role({"risk_level": "L2", "role": "arquitetos-software", "phase": "design"})

→ returns practice assignments + user stories to use as acceptance criteria.

4. Structure the threat model​

Recommended model (STRIDE adapted to the output):

## Threat Model — <componente>

### Componente em análise
- Surface: <endpoint, mĂłdulo, dataflow>
- Risk level: L2
- Concerns: auth, api, validation, encryption, logging

### Data flow (DFD)
<diagrama mermaid ou descrição>

### Threats (manual-grounded)

#### MT-NNN — <título da ameaça do output>
- **Descrição:** <`name` do output do MCP>
- **STRIDE:** <`threat_category`>
- **Mitigated by:** `CTRL-<domain>-<slug>-<hash>` (do `mitigated_by`)
- **Mitigation confidence:** derived · strength parcial ✅
- **Acceptance criteria:** <user stories de get_guide_by_role>

#### MT-NNN — <outra ameaça, ligação fraca>
- **Mitigation confidence:** *fallback* sem ligação estrutural → rotular como **inferido** ⚠️
- **Nota:** validar com revisĂŁo humana / testes.

### Threats sem mitigação no manual
- <`MT-*` devolvidos sem `mitigated_by`> — flag para revisão humana

### ResĂ­duo
<o que não foi endereçado>

Output discipline​

  • mitigation_confidence: "derived" (strength typically "parcial") → structural link. Present it as a reliable link.
  • Fallback without a structural link → treat as inferred; label it explicitly, not as a certainty.
  • If threats: [] → write "No threats catalogued in the manual for this scope — not to be confused with absence of risk". Do not invent.
  • Cite MT-* and CTRL-* IDs exactly as returned.

Skill / subagent — Cursor​

.cursorrules, dedicated section:

## Threat modeling com SbD-ToE

Quando for pedido threat model ou análise de ameaças:

1. Identificar concerns aplicáveis a partir do escopo do sistema.
2. Chamar mcp__sbd-toe__get_threat_landscape(risk_level, concerns).
3. Chamar mcp__sbd-toe__get_guide_by_role(risk_level, role, phase) para acceptance criteria.
4. Estruturar relatĂłrio STRIDE-adaptado citando MT-* e CTRL-* exactos.
5. Rotular mitigation_confidence (derived/parcial); ligação fraca → inferido.
6. Não inventar threats nem ligações. Threats vazios → flag para revisão humana.

Anti-patterns​

  • ❌ Calling consult_security_requirements before get_threat_landscape — unnecessary duplication; the tool already runs consult internally.
  • ❌ Presenting an inferred link (without mitigation_confidence: "derived") as a certainty.
  • ❌ Inventing MT-CUSTOM-001 to fit a threat that is known but not in the output — write it in a separate section as an observed threat and mark it not verified in the manual.
  • ❌ Confusing technical concerns (auth) with STRIDE domains (Spoofing).

Related​