
Threat Modeling
- 83 installs
- 129 repo stars
- Updated August 4, 2026
- bitwarden/ai-plugins
threat-modeling is a Claude skill that produces threat-model artifacts (data flow diagrams, security definitions, STRIDE threats) for new features or architecture changes.
About
This skill produces threat-model artifacts for new features or architecture changes. A developer uses it to create data flow diagrams, write security definitions (threat model plus security goals), and identify threats with STRIDE during an initial security assessment. It includes scoping rules such as pruning dominated threats, including honest-but-curious passive observers, and reality-checking goals against the runtime.
- Produces threat model artifacts: data flow diagrams and security definitions
- Identifies threats using the STRIDE framework in Bitwarden's 4-phase model
- Scopes threat models with rules on dominated threats and passive observers
Threat Modeling by the numbers
- 83 all-time installs (skills.sh)
- Ranked #1,076 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
threat-modeling capabilities & compatibility
- Capabilities
- security audit
- Use cases
- security audit
- Pricing
- Free
What threat-modeling says it does
This skill should be used when the user asks to "create a threat model", "define security goals", "generate a data flow diagram", "write security definitions"
Identify initial threats using STRIDE (see `references/stride-framework.md`)
Each definition has three components: a **threat model** (attacker capabilities), **security goals** (what the system guarantees), and an **accepted goal status**
npx skills add https://github.com/bitwarden/ai-plugins --skill threat-modelingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 83 |
|---|---|
| repo stars | ★ 129 |
| Last updated | August 4, 2026 |
| Repository | bitwarden/ai-plugins ↗ |
What it does
Produce a threat model: data flow diagrams, security definitions, and STRIDE-based threat identification for a feature.
Who is it for?
Engineers performing an initial security assessment and writing security definitions for a new feature.
Skip if: Reviewing an already-built system's auth and encryption design (use reviewing-security-architecture) or triaging scanner findings.
When should I use this skill?
You need to create a threat model, define security goals, generate a data flow diagram, or perform an initial security assessment.
What you get
A feature has data flow diagrams, scoped security definitions, and STRIDE-identified threats with goal rationales.
- Data flow diagrams
- Security definitions (threat model + goals)
- STRIDE threat list
By the numbers
- 4-phase engagement model
- STRIDE-based threat identification
- 3-component security definitions (threat model, goals, status)
Files
Bitwarden's Engagement Model
Bitwarden follows a 4-phase engagement model for security work. This skill primarily supports Phase 1 (engineering-owned) and assists with Phase 2-4 artifacts.
Phase 1: Initial Security Assessment (Engineering Team)
1. Create data flow diagrams (Mermaid, Excalidraw, or Structurizr) 2. Define security requirements separate from product requirements 3. Propose security definitions (threat model + security goals) 4. Identify initial threats using STRIDE (see references/stride-framework.md)
Phase 2: AppSec Team Review (AppSec + Engineering)
- Share data flow diagrams and security definitions in advance
- Walk through system architecture collaboratively
- Validate or refine proposed security definitions
- Identify additional threats, assess risk
- Avoid assuming external mitigations exist
Phase 3: Implementation (Engineering Team)
- Implement necessary security mitigations
- Create Jira follow-up work for threats without existing protections
- Include security considerations in sprint planning
Phase 4: Testing & Validation (Engineering + AppSec)
- Verify mitigations work as intended
- Adopt adversarial mindset during code review
- Test hypotheses (e.g., "Can I bypass SSO?") by working backwards
- Update security definitions as the system evolves
Security Definitions
Security Definitions (SDs) are Bitwarden's formal construct for communicating the security posture of a system. Each definition has three components: a threat model (attacker capabilities), security goals (what the system guarantees), and an accepted goal status (honest assessment of whether the goal is currently met).
Use Bitwarden's standard vocabulary when writing definitions — see references/bitwarden-vocabulary.md for the full glossary. Align security goals with Bitwarden's security principles (P01-P06) — see references/security-principles.md.
Threat Model Component
Describe attacker capabilities AND limitations — what they can and cannot do. Always state both sides to scope the definition precisely:
- "Attacker can run a user space process after the user's client has logged out" + "Attacker does not have access to secure storage mechanisms"
- "Attacker has database access and can read and write to the Send table" + "Attacker does not have access to the ASP.NET Core Data Protection encryption keys"
Include concrete examples where helpful (e.g., "An example for this is a stolen device"). Don't assume external mitigations are in place — even if obtaining an auth token is difficult, still explore what happens if an attacker has one.
Apply these rules when scoping the threat model:
- Prune dominated threats. If the attacker capability you're describing is strictly weaker than one already accepted as out-of-scope, delete the SD — its residual-risk statement collapses to a tautology like "equivalent to full user-account compromise". See
references/writing-quality-sds.mdfor the dominated-threat anti-pattern and the term Dominated Threat inreferences/bitwarden-vocabulary.md. - Include passive observers, not just adversaries. For any secret or protected data that crosses into an external service (LLM provider, log aggregator, analytics pipeline, training-data collector), write at least one SD whose attacker is honest-but-curious. Confidentiality harms often arise from _visibility_, not malice — an adversarial framing alone misses the baseline concern. See the Passive Observer vocabulary entry.
- Verify "attacker does not have X" against the target platforms. Every limitation must be factually true on every OS/runtime in scope. Common pitfall: assuming kernel-level privileges are required for a capability that is actually unprivileged on Linux and Windows (e.g., reading another process's environment). If the limit isn't true, the SD is mis-scoped.
Security Goals Component
State concise, testable guarantees about what cannot happen given the threat model. Reference specific assets (tokens, keys, vault data):
- "Valid tokens cannot be accessed by attacker after the user's client has logged out"
- "Attacker cannot retrieve any decrypted MasterKeys that do not belong to them"
- "Attacker can perform reads on encrypted email addresses lists only"
Every goal carries a Rationale — three pieces, one line each:
- Principle — which Bitwarden principle (P01–P06) the goal enforces. See
references/security-principles.md. - Asset — the specific data, key, or token being protected.
- Harm — the user-visible consequence if the goal is violated (e.g., "master password exposed to third-party LLM provider and potentially their training pipeline").
A goal without a rationale is a claim, not a requirement. Rationales let reviewers judge whether the goal is load-bearing or can be cut.
Two additional rules on goal framing:
- Reality-check goals against runtime. Goals that claim a secret is "cleared from memory", "zeroized", or "not retained" are unenforceable in garbage-collected, string-interned runtimes (JavaScript, .NET, JVM, Python). If the runtime cannot uphold the goal, restate it in terms of what the runtime _can_ guarantee (scope minimization, short-lived references, process isolation), or mark Accepted Goal Status as explicitly not met and link the systemic limitation. Do not write goals the language cannot back.
- Prefer stdin or file-descriptor handoff over env/argv for secrets. If the goal forbids secret exposure to
process.envorargv, the implementation MUST use stdin or an inherited file descriptor. An SD whose goal forbids env exposure but whose implementation passes the secret through env is internally inconsistent — fix the design, or fix the goal, but do not ship both.
Accepted Goal Status Component
Provide an honest assessment of the current state:
- Goal is met — Explain how (e.g., "User state clearing includes removal of the stored token from disk")
- Goal is partially met — Break down what works and what doesn't, using separate indicators for each aspect
- Goal is not met — Explain the gap and why it is accepted
- Best Effort — For goals dependent on platform capabilities (e.g., "This goal is not upheld for clients that do not have access to secure storage such as web and browser")
When a goal is known to be broken, link to the relevant tracking issue. Note scoping caveats (e.g., "These definitions do not apply in the case of a Vault Timeout set to Never").
Two additional rules:
- Quantify "brief" or "short-lived" rationales. If acceptance of residual risk rests on "the exposure is short", state the bound. For example: "Secret resides in the child process env for the duration of
bw unlock, which scales with KDF iterations and vault size — observed between 1 and 8 seconds on representative hardware." _Brief without a number is not an accepted status — it is a hope._ See the Exposure Window vocabulary entry. - Enforce internal consistency. The Threat Model, Security Goal, and Accepted Goal Status must agree. If the threat model puts capability X in-scope, the goal must defend against X, and the status must say whether that defense holds. If the goal forbids env exposure but the implementation uses env, the SD is wrong — pick which of the three to change and change it. Inconsistency is not a style issue; it is the SD failing to describe the system.
Writing Security Definitions
- It's OK to be wrong — the purpose is to start the conversation and see if these can be broken
- Start with what the system SHOULD guarantee, then validate through threat analysis
- Separate macro-level definitions (e.g., end-to-end encryption) from micro-level definitions specific to the feature
- Number definitions sequentially (SD1, SD2, SD3) — each is a self-contained unit
- Include a glossary of feature-specific terms when the feature introduces domain-specific vocabulary
- Prioritize by impact, not by enumeration. A short document listing the 3–5 threats that actually shape the design is more useful than a 15-SD document that buries the important ones in noise. Before adding an SD, ask: _"If this threat didn't exist, would the design change?"_ If the answer is no, it is likely code-quality commentary, not a security definition.
- Tag each SD with a Criticality level (Critical / High / Medium / Low) and order the document by Criticality descending, so reviewers see the load-bearing SDs first. See
references/writing-quality-sds.mdfor the prioritization heuristic. - Verbosity is a failure mode. The same anti-pattern that plagued early LLM code review — long lists with low signal — also plagues generated security definitions. Cut SDs that describe implementation-detail concerns (e.g., a future maintainer editing a constant to contain shell metacharacters) unless they are load-bearing to the design.
Artifact Generation
Use the templates in examples/ when generating artifacts:
- `examples/security-definition-document.md` — Full SD document template with glossary, numbered definitions, Criticality tagging, goal rationale, and accepted goal status
- `examples/data-flow-diagram.md` — Mermaid DFD template with trust boundaries
- `examples/threat-catalog.md` — Threat catalog table and mitigation tracking templates
Consult these references when writing or reviewing SDs:
- `references/writing-quality-sds.md` — Anti-patterns (dominated threats, adversarial-only attackers, unenforceable goals, aspirational limitations, shell-quoting SDs, the "brief exposure" trap) and the self-consistency checklist
- `references/bitwarden-vocabulary.md` — Standard terms, including Passive Observer, Dominated Threat, and Exposure Window
- `references/security-principles.md` — P01–P06, referenced by every goal's Rationale line
- `references/stride-framework.md` — STRIDE categories for structured threat identification
When to Engage AppSec
Teams should initiate a full engagement with the AppSec team (#team-eng-appsec) when:
- Greenfield projects or new services
- Data sharing modifications (organization memberships, Send, sharing features)
- New IPC channels between components
- Cross-domain or cross-origin functionality
- Uncertain about security implications — perform an Initial Security Assessment first and post findings to #team-eng-appsec with a note indicating uncertainty about whether a full engagement is needed
Quick questions (e.g., concerns about a third-party library or coding practice) don't need a full engagement — post those directly to #team-eng-appsec.
Critical Rules
- Separate product requirements from security requirements in tech breakdowns. They serve different purposes and have different stakeholders.
- Security definitions are living documents. Revisit them when features change, new threats emerge, or security issues are discovered.
- Complexity increases vulnerability risk. Flag overly complex security-critical code as tech debt. Complex code with numerous dependencies and intricate logic is exceptionally challenging to secure.
- Threat modeling will never identify all vulnerabilities. It's one tool among many. Balance it with code analysis, security testing, and adversarial review.
- Don't assume external mitigations. When defining the threat model, explore what happens if an attacker bypasses external controls.
- Dominated or implementation-trivial threats are noise. Cut SDs whose residual-risk text reduces to "equivalent to full user-account compromise" or whose only mitigation is "reviewers notice a constant being edited". They degrade signal-to-noise and hide the threats that actually matter.
- Every security goal carries a rationale. Tie each goal to a Bitwarden principle (P01–P06), the protected asset, and the user-visible harm. Goals without rationales cannot be prioritized or evaluated for necessity, and tend to survive review by inertia rather than merit.
Before finalizing a set of SDs, apply the self-consistency checklist in references/writing-quality-sds.md.
Data Flow Diagram Template
Use Mermaid syntax for text-based DFDs that can be version-controlled.
Bitwarden is moving toward a Structurizr-based approach for persistent architecture diagrams. For ad-hoc threat modeling, Mermaid or Excalidraw are acceptable.
Example
graph LR
subgraph Trust Boundary: Client
A[Browser Extension] --> B[Client SDK]
end
subgraph Trust Boundary: Network
B -->|TLS| C[API Gateway]
end
subgraph Trust Boundary: Server
C --> D[Identity Service]
C --> E[API Service]
E --> F[(Database)]
E --> G[Key Management]
end
style A fill:#e1f5fe
style F fill:#fff3e0Required Elements
Include: components, data stores, external entities, data flows with protocols, and trust boundaries.
Security Definition Document Template
Use this template when creating security definitions for a new feature or system.
Order Security Definitions (SDs) by Criticality descending. Reviewers anchor on what they see first — lead with the load-bearing threats.
Every Security Goal must carry a Rationale line linking the goal to a Bitwarden principle (P01–P06), the protected asset, and the user-visible harm. Goals without rationale are claims, not requirements.
When an Accepted Goal Status says a secret's exposure is "brief", "short-lived", or "transient", quantify the window — state a typical and worst-case duration. "Brief" without a number is a hope, not a status.
# [Feature Name] Security Definitions
[Link to macro-level security definitions and any parent feature documentation.]
[Optional scoping caveat, e.g., "These security definitions do not apply
in the case of a Vault Timeout set to `Never`."]
## Glossary
- **[Term]**: [Feature-specific definition]
- **[Term]**: [Feature-specific definition]
---
## SD1: [Concise threat scenario title]
**Criticality:** Critical | High | Medium | Low
### Threat Model
- Attacker can [capability]
- An example for this is [concrete scenario]
- Attacker does not have [limitation that scopes this definition — verified against every supported OS]
### Security Goal
- [Concise, testable guarantee about what cannot happen]
- **Rationale:** Enforces [P0X: Principle Name]; protects [asset: token/key/vault data/password]; harm if violated is [user-visible consequence, e.g., "master password visible to third-party LLM provider and potentially their training pipeline"].
### Accepted Goal Status
- ✅ Goal is met:
- [Explanation of how the goal is satisfied in the current implementation]
---
## SD2: [Concise threat scenario title]
**Criticality:** Critical | High | Medium | Low
### Threat Model
- Attacker is a **Passive Observer** — [e.g., the LLM provider receiving tool I/O, a log aggregator, a telemetry pipeline]. No malicious intent required; the harm arises from visibility during normal operation.
- Attacker does not have [limitation]
### Security Goal
- [What the system guarantees]
- **Rationale:** Enforces [P0X]; protects [asset]; harm if violated is [consequence].
### Accepted Goal Status
- Goal is **partially** met:
- ✅ [Aspect that is satisfied]
- ❌ [Aspect that is not satisfied — include quantified exposure window if acceptance rests on "brief" duration, e.g., "secret resides in child-process env for 1–8 s depending on KDF iterations and vault size"]
---
## SD3: [Concise threat scenario title]
**Criticality:** Critical | High | Medium | Low
### Threat Model
- Attacker can [capability]
- Attacker does not have [limitation]
### Security Goal
- [What the system guarantees]
- **Rationale:** Enforces [P0X]; protects [asset]; harm if violated is [consequence].
### Accepted Goal Status
- ❌ Goal is **not** met:
- [Explanation of the gap. If the goal is unenforceable due to runtime constraints — e.g., memory zeroization in a GC'd, string-interning runtime — state the systemic limitation here and link any tracking issue. Do not write a goal the language cannot back.]Before shipping
Apply the self-consistency checklist in `../references/writing-quality-sds.md`:
1. Does each goal defend against every in-scope threat-model capability? 2. Is every goal realizable by the runtime? 3. Is every "attacker does not have X" true on every supported OS? 4. Is there a passive-observer SD wherever a secret crosses an external-service boundary? 5. Is every SD tagged with Criticality, and is the document ordered Criticality-descending?
Threat Catalog and Mitigation Tracking Templates
Threat Catalog
| # | Threat | STRIDE | Component | Existing Mitigation | Proposed Mitigation | Risk Level |
|---|---|---|---|---|---|---|
| 1 | Description | S/T/R/I/D/E | Affected component | What exists today | What should be added | Critical/High/Medium/Low |
Mitigation Tracking
For threats without existing mitigations, document for Jira follow-up:
## Unmitigated Threat: [Title]
- **Threat:** [Description]
- **STRIDE Category:** [Category]
- **Affected Component:** [Component]
- **Impact:** [What happens if exploited]
- **Proposed Mitigation:** [What to implement]
- **Priority:** [Based on risk assessment]Bitwarden Security Vocabulary
Standard terminology for use in security definitions. Sourced from Security Definitions.
Core Terms
- Vault Data — A user's private information stored in Bitwarden (passwords, usernames, secure notes, credit cards, identities, attachments)
- Protected Data — Data stored in unreadable format (typically encrypted) with expectations about secure key storage
- Data at Rest — Stored data not actively used or transmitted (disk storage on devices or servers)
- Data in Use — Data actively being processed or accessed, held in volatile memory
- Data in Transit — Data actively transferred between locations, processes, or devices
- Secure Channel — A communication channel providing confidentiality (unreadable to unauthorized parties) and integrity (tamper-proof)
- Trusted Channel — A secure channel that also provides authenticity (verified identities of communicating parties)
- Data Exporting — Controlled process where data leaves Bitwarden unprotected, nullifying security guarantees. Requires informed and explicit consent.
- Data Sharing — Controlled data exchange within the Bitwarden secure environment (security guarantees maintained)
- Data Leaking — Unintentional departure of data from Bitwarden unprotected
- Bitwarden Secure Environment — Any process or application adhering to Bitwarden's security standards
Threat-Modeling Terms
- Passive Observer — An entity that sees data during normal operation without acting maliciously (e.g., LLM providers receiving tool I/O over the API, log aggregators, analytics pipelines, training-data collectors). Used to frame confidentiality harms that arise from _visibility_, not _attack_. Every SD involving a secret that crosses an external-service trust boundary should include at least one passive-observer framing.
- Dominated Threat — A threat whose attacker capabilities are strictly weaker than those of another threat already accepted as out-of-scope. Dominated SDs are pruned because their residual-risk statements collapse to tautologies (e.g., "equivalent to full user-account compromise"). They contribute no new information and dilute the signal of the SD document.
- Exposure Window — The bounded duration a secret is accessible in a less-protected context (e.g., a password held in child-process environment variables during an unlock operation). When Accepted Goal Status justifies residual risk on the grounds that exposure is "brief" or "short-lived", the window MUST be quantified (typical and worst-case duration).
Bitwarden Security Principles (P01-P06)
These six principles form the foundation for all threat modeling at Bitwarden. Reference them when writing security goals and evaluating threats.
Sourced from Security Principles.
Principles
| Principle | Name | Core Guarantee |
|---|---|---|
| P01 | Servers are Zero Knowledge | Bitwarden infrastructure cannot access unencrypted user data. The server must not enable weakening of user-chosen protections, masquerade server data as user-encrypted content, or access encrypted data outside the client context. |
| P02 | A Locked Vault is Secure | Highly sensitive vault data cannot be accessed in plaintext once the vault is locked, even if the device is compromised after locking. Platform limitations (e.g., JS memory) are mitigated through buffer clearing and available security features. |
| P03 | Limited Security on Semi-Compromised Devices | For unlocked vaults on devices with userspace malware (but intact OS/kernel), clients maximize kernel/OS-level protections and balance security with usability through controls like biometrics. |
| P04 | No Security on Fully Compromised Systems | Bitwarden cannot guarantee vault protection when hardware or OS-level integrity is fully compromised. This applies to unlocked vaults only — locked vaults are covered by P02. |
| P05 | Controlled Access to Vault Data | Vault data, whether at rest or in use, is accessible only to authorized parties under the user's explicit control. Isolation mechanisms are critical in high-risk environments like web browsers. |
| P06 | Minimized Impact of Security Breaches | Limit breach scope and duration through session invalidation, key rotation (countering "harvest now, decrypt later"), and post-compromise security (new data remains protected after a breach). |
Controlled Exceptions
Principles have documented exceptions. When threat modeling, check the full principles documentation for current exceptions.
Known examples:
- P01 — Key Connector: Self-hosted SSO without passwords. The server holds encryption keys on behalf of the user.
- P01 — Icons Service: Plaintext domain names are sent to retrieve favicons.
Security Requirements
Security requirements define concrete MUST/SHOULD/MAY obligations organized by category. Reference these when validating that a design satisfies Bitwarden's security standards.
Full requirements: Security Requirements
| Category | Scope | Key Obligations |
|---|---|---|
| VD | Vault Data | Protected at rest (encrypted with UserKey), allowed in use (decrypted during unlock), trusted channels in transit, export requires informed consent |
| EK | Encryption Keys | 256-bit security strength, protected at rest and in transit, must never be exported |
| AT | Authentication Tokens | Protected storage at rest, mandatory transit protection |
| SC | Secure Channels | Confidentiality, integrity, replay prevention, forward secrecy for long-lived channels |
| TC | Trusted Channels | Secure channel properties plus receiver identity verification |
STRIDE Framework
Use STRIDE as a guide for structured threat identification. Some vulnerabilities won't map cleanly to STRIDE — that's expected.
| Category | Question to Ask | Example Threats | Typical Mitigations |
|---|---|---|---|
| Spoofing | Can an attacker impersonate a user or component? | Forged auth tokens, session hijacking, credential stuffing | Strong authentication, token validation, MFA |
| Tampering | Can an attacker modify data in transit or at rest? | Man-in-the-middle, database manipulation, parameter tampering | Integrity checks, signed payloads, TLS, input validation |
| Repudiation | Can an attacker deny performing an action? | Missing audit logs, unsigned transactions | Audit logging, digital signatures, timestamps |
| Information Disclosure | Can an attacker access data they shouldn't? | Verbose errors, insecure storage, side-channel leaks | Encryption, access controls, error sanitization |
| Denial of Service | Can an attacker degrade or prevent service? | Resource exhaustion, algorithmic complexity attacks | Rate limiting, input size bounds, circuit breakers |
| Elevation of Privilege | Can an attacker gain unauthorized access? | Broken access control, privilege escalation, IDOR | Authorization checks at every layer, least privilege |
Writing Quality Security Definitions
Security definitions exist to communicate the security posture of a system to reviewers, auditors, and future maintainers. A noisy or poorly-scoped SD document is worse than a shorter honest one — it hides the threats that actually matter behind threats that do not.
This reference collects the recurring anti-patterns that degrade SD quality and the checks to apply before shipping.
Anti-patterns
1. The dominated threat
Symptom. An SD describes an attacker whose capabilities are strictly weaker than an attacker already accepted as out-of-scope. The residual-risk statement ends up saying "this is equivalent to full user-account compromise, which is outside our threat model."
Example. A tool that wraps a local CLI binary adds an SD about a malicious replacement of that binary on PATH. If the threat model already treats _full local-user compromise_ as out-of-scope, then a same-user attacker who can replace the binary could equivalently prompt the user for their password through any other mechanism — the threat reduces to one already accepted.
Why it's bad. The SD contributes no new information and consumes reviewer attention. Its presence suggests the document is comprehensive when it is really just long.
Fix. Delete the SD. If there is a _narrower_ concern worth keeping (e.g., the tool should refuse to run if the binary's path is not a known install location), write that narrower SD, not the dominated one.
2. The adversarial-only attacker
Symptom. An SD frames a confidentiality concern as an adversary actively trying to exfiltrate data, when the actual risk is _passive visibility_ during normal operation.
Example. A feature routes a master password through an external AI service. The generated SD reads: "A prompt-injected or malicious LLM attempts to trick the user into revealing their master password." The real threat is simpler and more serious: _the password is now visible to the LLM provider_, which may log it, surface it in support tooling, or incorporate it into training data. No malicious intent is required for the harm.
Why it's bad. Adversarial framing makes the threat feel exotic and low-probability when in fact the harm is inherent to the data flow. Reviewers may accept residual risk on the grounds that adversarial LLMs are rare, missing the systemic issue.
Fix. Whenever a secret or protected data crosses a trust boundary into an external service, write at least one SD whose attacker is an honest-but-curious Passive Observer (see vocabulary). If both the adversarial and passive framings are interesting, write both — but do not omit the passive one.
3. The unenforceable goal
Symptom. A security goal claims a secret is "cleared from memory", "zeroized", or "not retained", in a runtime that cannot make that guarantee.
Example. A Node.js server asserts that a session token MUST be cleared from process memory after use. JavaScript is garbage-collected and interns strings; there is no reliable way to overwrite a string's backing storage or to force eviction. The goal is unenforceable by any mechanism available to the application.
Why it's bad. Unenforceable goals erode trust in the document. Either the reviewer catches the contradiction and the SD loses credibility, or they don't and the document misrepresents the system's security posture.
Fix. Restate the goal in terms the runtime _can_ enforce — minimize the number of references, keep the secret scoped to the shortest possible function/process lifetime, isolate into a child process or separate process, use language features that provide zeroization when available (e.g., Rust's Zeroize, SDK boundaries). If none of those apply, mark Accepted Goal Status as explicitly _not met_ and link to the systemic runtime limitation so the honest answer is on record.
4. The aspirational limitation
Symptom. A threat-model limitation ("Attacker does not have X") assumes a privilege level that is not actually required for the capability in question on the target platforms.
Example. An SD claims the threat model excludes "attackers with kernel-level privileges" as justification for why a secret in process environment variables is safe. On Linux (per-user process visibility via /proc/<pid>/environ) and on Windows (via unprivileged APIs on the same user session), reading another process's environment does not require kernel privileges. The limit is aspirational, not factual.
Why it's bad. The SD's entire scoping depends on a limitation that does not hold, so its conclusions are unsound. Worse, the limitation _sounds_ reassuring, so downstream readers may build on it without checking.
Fix. For every "Attacker does not have X" clause, verify X actually requires the privilege claimed on every OS/runtime in scope. If not, either narrow the clause ("Attacker does not have another process running under the same user account") or accept the broader capability and restate the goal to defend against it.
5. The shell-quoting SD
Symptom. An SD describes a threat where a future maintainer edits a hardcoded constant to contain shell metacharacters (backticks, $, backslashes, newlines), breaking out of a quoted string into arbitrary code execution.
Example. An SD reads: "Attacker is a future maintainer who edits DIALOG_TITLE to contain quotes or backticks, breaking out of the AppleScript string context." The only mitigation available is "code review notices the constant change" — which is code quality practice, not a security control.
Why it's bad. The mitigation is "don't edit the constant in a dangerous way", which is not a security boundary. These SDs conflate secure-coding practice with threat modeling. They are almost always low-criticality and generate noise that masks higher-criticality SDs.
Fix. Do not write an SD whose only mitigation is code review or author discipline. If the constant truly needs to be treated as tainted input, refactor the code to handle it safely (parameterized execution, no shell interpolation). The safety is then a property of the implementation, not an SD.
6. The "brief exposure" trap
Symptom. Accepted Goal Status justifies residual risk with "brief", "short-lived", or "transient" — without a number.
Example. "The secret is held in child-process environment for only a brief window during unlock" — when unlock duration scales with KDF iterations and vault size, and may run for several seconds on representative hardware. During that window, every process running under the same user can observe it.
Why it's bad. "Brief" is a hope, not a bound. It lets reviewers mentally round down to "instant" when the real window may be long enough to matter for an attacker with a concurrent process.
Fix. Quantify the exposure window. State the typical and worst-case duration, and name what is running that could observe it. If you cannot quantify it, you cannot claim it is short enough to accept — remove the acceptance rationale and treat the goal as not met.
Self-consistency checklist
Run these five checks before shipping a set of SDs. If any fails, fix the SD — do not ship it and rely on reviewers to catch the inconsistency.
1. Spec ↔ implementation. For every capability the threat model puts in-scope, does a goal defend against it, and does the implementation actually uphold that defense? If the goal forbids exposure to process.env but the implementation passes the secret through env, the SD is wrong. 2. Runtime feasibility. Can the language/runtime actually uphold every goal as written? Flag any goal that relies on memory clearing, zeroization, or non-retention in a GC'd / interned-string runtime. 3. Platform reality. For every "Attacker does not have X" clause, is X actually restricted on every supported OS? Reading another process's env, enumerating open handles, and inspecting argv are not kernel-privileged on common platforms. 4. Passive-observer coverage. For every secret or protected datum that crosses into an external service (LLM provider, log aggregator, analytics, training pipeline), is there an SD with a passive/honest-but-curious attacker? Adversarial framing alone is not sufficient. 5. Criticality and ordering. Does every SD carry a Criticality tag (Critical / High / Medium / Low), and is the document ordered by Criticality descending? If not, the reader will anchor on whichever SD appears first, not the one that matters most.
Prioritization heuristic
Before including an SD, ask: _"If this threat did not exist, would the design change?"_
- Yes → the SD is load-bearing. Keep it.
- No → the SD is commentary. Cut it, or move it to a secure-coding notes section that is clearly not part of the SD document.
A 5-SD document that survives this filter is more valuable than a 15-SD document that does not. Verbosity is a failure mode — the early iterations of LLM-generated code review taught the organization this lesson already, and the same dynamic applies to LLM-generated security definitions.
Related skills
FAQ
What framework does it use to identify threats?
STRIDE, applied during Phase 1 initial security assessment, with a bundled stride-framework reference.
What is a security definition?
A formal construct with three parts: a threat model of attacker capabilities, security goals, and an accepted goal status.