Every Feature Ships with a Threat Model

Security works best when it’s part of the design. When you think about threats at the same time you think about features, the mitigations become natural — woven into the architecture rather than layered on top. That’s the approach we take with CrispyVibe.

Every feature ships with a threat model. It’s how we build confidence.

The four-document convention

Every feature in CrispyVibe is defined by exactly four documents:

specs/features/{domain}/{feature-name}/
  spec.md              ← What it does (requirements, scenarios)
  technical-design.md  ← How it's built (architecture, data flow)
  threat-model.md      ← What we protect against (attacks, mitigations)
  usage-guide.md       ← How the user uses it

The threat model sits alongside the spec as an equal. Whether the feature is a theme picker or an SSH remote session, we think through its security surface upfront. This gives us confidence that every feature is considered holistically from day one.

Anatomy of a threat model

Each threat model follows a consistent structure:

  1. Overview — what the feature touches and its boundaries
  2. Trust boundaries — where data crosses privilege levels
  3. Attack surfaces — what’s exposed
  4. Threats — each with a vector, impact, likelihood, and mitigation
  5. Residual risks — what we’ve accepted and why
  6. NFR compliance — how the feature satisfies cross-cutting requirements

Every threat gets a tracked ID (F046-T01, F046-T02, …) that links back to the feature spec. This makes the security story auditable and traceable across the codebase.

A real example: protecting credentials

Here’s a threat from Terminal Scroll Assist (F046-T06):

Vector: User types a password at a hidden prompt (sudo, ssh, read -s). Input recording could capture these keystrokes and surface them via history navigation.

Impact: Credential disclosure within the app’s in-memory state.

Likelihood: High — password prompts are a daily occurrence.

Mitigation: recordInput() validates screen visibility before publishing. On Enter, it reads the terminal render buffer and checks if the typed text appears on screen. Terminals disable echo for secret input, so hidden text is invisible in the buffer and is automatically excluded from recording.

This threat was identified during spec writing — before implementation began. The mitigation was designed into the architecture from the start, giving us confidence that credentials are protected by construction.

NFR traceability

Every mitigation links to a non-functional requirement (NFR) that applies across the entire application:

NFRWhat it ensures
SEC-1Process isolation — minimum privileges, typed IPC
SEC-2Data at rest — integrity verification, secure storage
SEC-3Content security — CSP, sanitization, typed commands
SEC-3aInput sanitization — validation on all input sources
SEC-5Code execution boundaries — explicit user action required
SEC-7File system scope — symlink-safe, scoped to project
PERFPerformance — responsiveness, efficient resource use
A11YAccessibility — keyboard navigation, screen readers
OBSObservability — logging, diagnostics

When a threat model says “Linked NFR: SEC-Data-Protection,” that’s a traceable connection to a requirement with its own verification criteria. If the NFR evolves, every feature referencing it is reviewed — keeping the whole system coherent.

Why this works well

It catches things early. The credential capture threat above was identified during spec writing. By thinking about it upfront, we designed the mitigation into the feature architecture — it shipped as part of the feature, ready from day one.

It scales beautifully with AI-assisted development. When AI writes code, it follows the spec. When the spec includes a threat model, the AI implements the mitigation as part of the feature. The threat model becomes part of the implementation contract that AI agents can follow.

It creates shared understanding. Six months from now, when someone modifies the input recording system, the threat model is right there in the feature folder. The security context travels with the code — always accessible, always current.

It makes security collaborative. Instead of security being a gate at the end, it’s a conversation at the beginning. The threat model is a design document that the whole team can contribute to and learn from.

The process

  1. Write the spec — define requirements and scenarios
  2. Write the threat model — identify trust boundaries, attack surfaces, threats
  3. Link to NFRs — connect each mitigation to a cross-cutting requirement
  4. Write the technical design — architecture incorporates mitigations naturally
  5. Implement — code follows the design, which already includes security
  6. Verify — NFR compliance table serves as a confidence checklist

The convention is part of the development workflow — AI agents produce all four documents, and features are considered complete when they have them.

The result

CrispyVibe has 45+ threat models across every feature domain — terminals, editors, AI agents, browser, SSH, file explorer, authentication, and platform services. Each one traces back to 8 NFR categories. Every security decision is documented, traceable, and reviewable.

This approach is about building confidence systematically. When every feature has a threat model, you know what was considered. You know what’s protected. You know what the residual risks are and why they’re acceptable. That clarity compounds over time into a codebase you can trust.

Thirty minutes of threat modeling per feature buys you confidence that compounds forever.

The four-document convention is lightweight — it adds maybe 30 minutes per feature. What it gives back is a codebase where security decisions are visible, traceable, and designed in from the start.

Every feature ships with a threat model. That’s how CrispyVibe builds security by design — systematically, collaboratively, and with confidence.