The Gitea issue body is the single source of truth for a spec; the only per-feature artifact in git is the RTM row (REQ-ID -> issue # -> test). Drops per-feature spec.md/tasks.md/checklist files from the workflow (the _example stays as a template/reference). Updates the guide, ADR-041, AGENTS.md, CLAUDE.md, templates, the RTM (adds an Issue column), the implement/review-pr skills, and replaces the file-spec CI jobs with an rtm-check. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
54 lines
2.9 KiB
Markdown
54 lines
2.9 KiB
Markdown
<!--
|
||
Threat model template — STRIDE + ASTRIDE. WRITING AID: fill this in and paste the result into
|
||
the issue's "## Security Considerations" section (issue-only — the threat model lives in the
|
||
issue body, not a committed file). Required when a feature adds a new trust boundary, handles
|
||
uploads, exposes a new mutating endpoint, or invokes an AI agent/tool. The Security persona
|
||
gates it during /review-issue. Delete this comment.
|
||
-->
|
||
|
||
# Threat Model — <Feature name>
|
||
|
||
**Feature spec:** Gitea issue #<n>
|
||
**Date:** <YYYY-MM-DD>
|
||
**Author:** <name>
|
||
|
||
## Data Flow Diagram (text)
|
||
|
||
**Actors**
|
||
- <e.g. Anonymous visitor, Authenticated reader, Authenticated transcriber, Admin, OCR sidecar>
|
||
|
||
**Trust boundaries**
|
||
- TB-1: Browser ⇄ Caddy (public internet ⇄ DMZ)
|
||
- TB-2: Caddy ⇄ Backend (`:8080`) (DMZ ⇄ app)
|
||
- TB-3: Backend ⇄ PostgreSQL / MinIO / sidecars (app ⇄ data plane)
|
||
- <add feature-specific boundaries>
|
||
|
||
**Data flows** (source → [boundary] → sink : data)
|
||
- F-1: Browser → [TB-1,TB-2] → Backend : <request payload>
|
||
- F-2: Backend → [TB-3] → MinIO : <stored object>
|
||
- <…>
|
||
|
||
## STRIDE
|
||
|
||
| Threat Category | Asset / Flow | Threat Description | Mitigation | Likelihood × Impact | Status |
|
||
|---|---|---|---|---|---|
|
||
| **S**poofing | <asset> | <e.g. unauthenticated caller forges a request> | <session auth + @RequirePermission> | Low × High | <Open/Mitigated/Accepted> |
|
||
| **T**ampering | <asset> | <e.g. mass-assignment of createdBy> | <server-set audit fields, no body binding> | Med × High | |
|
||
| **R**epudiation | <asset> | <e.g. no record of who changed what> | <NOT NULL createdBy/updatedBy audit trail> | Low × Med | |
|
||
| **I**nformation disclosure | <asset> | <e.g. entity leaks email/hash; raw 500 leaks Hibernate internals> | <view not entity; DomainException.conflict> | Med × High | |
|
||
| **D**enial of service | <asset> | <e.g. oversized upload / unbounded list> | <size limit, batch cap, pagination> | Med × Med | |
|
||
| **E**levation of privilege | <asset> | <e.g. reader reaches a write endpoint / IDOR> | <least-privilege Permission, ownership check> | Low × High | |
|
||
|
||
## ASTRIDE (only if the feature invokes an AI agent / tool — OCR, NLP, LLM)
|
||
|
||
| Threat | Asset / Flow | Threat Description | Mitigation | Likelihood × Impact | Status |
|
||
|---|---|---|---|---|---|
|
||
| Prompt Injection | <input to the model> | <untrusted document text steers the model> | <treat model output as untrusted; no auto-exec> | | |
|
||
| Context Poisoning | <retrieved/shared context> | <attacker plants data that biases later runs> | <scope/provenance of context; validation> | | |
|
||
| Unsafe Tool Invocation | <tool the agent can call> | <model triggers a privileged action> | <allow-list tools; human-in-loop on mutations> | | |
|
||
| Reasoning Subversion | <decision the model makes> | <crafted input flips a classification/decision> | <confidence threshold; deterministic guardrail> | | |
|
||
|
||
## Residual Risk
|
||
|
||
<Threats marked Accepted, who accepted them, and why the residual risk is tolerable.>
|