Blog · 2026-06-10 · ~12 min read

The security ADR: how to document decisions that affect threat model, data handling, or compliance scope

A Series A startup begins SOC 2 Type II audit prep. The auditor asks a reasonable question: what is your decision record for storing customer PII, what encryption decisions were made, and who reviewed those decisions before they went to production? The answer from the engineering team is honest and common: there isn't a formal record. The engineer who made the original data model decision moved on eight months ago. The choices about what to store, how long to keep it, and how to protect it at rest were made over a series of late-night Claude sessions during the initial build sprint. The reasoning was sound. Nobody wrote it down in a form that survives the engineer's departure and stands up to an external review. The startup now has two options: (1) document the decisions retrospectively, which means their accuracy depends on the memories of people who weren't in the room, or (2) recover the decision history from AI chat exports, which is what the original engineer's sessions actually contain. This is not an edge case. Every engineering team that reaches compliance audit stage has some version of this problem. The decisions that get reconstructed most painfully in the room with an auditor are the ones that were made carefully, by engineers who thought deeply about the trade-offs — in AI chat sessions that nobody ever exported.

TL;DR

Security decisions — those affecting threat model, data handling, encryption, access controls, or compliance scope — require a different ADR format than standard service-local decisions. The standard Nygard template's Consequences section doesn't distinguish accepted risks from desired outcomes, has no security reviewer field, no compliance scope annotation, and no review cadence. A security ADR adds five fields: threat model scope, data classification, compliance scope, security reviewers, and review triggers. It also has a classification problem: some security ADR content reveals attack surface and belongs in a private record, not a public ADR repository. The WhyChose extractor recovers the compliance research and security deliberation that engineers conducted in AI chat — the sessions where the actual trade-offs were worked out — before that reasoning is lost entirely.

What makes a decision security-relevant

Most architecture decisions don't have a compliance footprint. Choosing a background job library, picking a caching strategy, deciding how to structure the internal domain model — these are consequential decisions, but they don't implicate regulatory frameworks or create obligations for external review. Security decisions are different in kind.

Four categories reliably produce security-relevant decisions:

The practical test: if a hypothetical auditor — for SOC 2, GDPR, HIPAA, or an internal security review — would ask "what was the decision and what was the review process for it?", the decision needs a security ADR. When in doubt, err toward documenting it. An over-documented security decision log creates mild overhead; an under-documented one creates real liability at exactly the moment you can least afford it.

Why the standard ADR template falls short for security decisions

The standard Nygard ADR format — Title, Status, Context, Decision, Consequences — is purpose-built for technical decisions. Its Consequences section is designed to capture what becomes easier, what becomes harder, and what technical debt is accepted. This is the right structure for a background job library choice. It is incomplete for a security decision for three specific reasons.

First, the Consequences section conflates desired outcomes with accepted risks. When a security decision accepts a known risk — "we chose not to implement per-operation audit logging because the performance overhead is unacceptable at our current query volume; this means we cannot reconstruct exact read histories for audit purposes" — that accepted risk needs to be explicitly labeled as such, separated from the positive outcomes. In a standard Consequences section, it gets buried in a bullet point alongside "reduces database CPU by 12%." Auditors look for explicit risk acceptance statements, not inferred ones buried in trade-off lists.

Second, the standard template has no security reviewer field. The author and the technical decision-maker are the same person. For compliance purposes, the review by the security function is part of what the ADR needs to document — not just what was decided, but who reviewed it before it went to production. A SOC 2 auditor asking about your encryption-at-rest decision will want to know whether that decision was reviewed by someone other than the engineer who implemented it. The standard ADR format has no place to record this.

Third, most ADRs are written once and considered done. The lifecycle model for standard ADRs treats Accepted status as stable until the decision is explicitly superseded or deprecated. Security decisions don't work this way — their validity depends on external conditions that the engineering team doesn't control. An access control decision that was correct in 2023 may be wrong in 2026 if the threat model changed, the regulatory guidance updated, or the third-party processor you rely on for GDPR Article 28 compliance was acquired and changed their DPA. The standard ADR template has no mechanism for encoding when a security decision should be revisited.

The standard Markdown ADR template and MADR share these same gaps — they're both extensions of the Nygard model optimized for technical decision documentation, not compliance documentation. The additional fields a security ADR requires have to be added as a team-level convention; no standard template includes them by default.

The five fields a security ADR adds

These five fields are what distinguish an audit-ready security ADR from a general-purpose one. They sit below the standard Consequences section and above any Further Reading or related ADRs:

  1. Threat model scope. What threats does this decision address, and what threats does it explicitly accept or defer? This is different from the Context section, which describes the technical situation. The threat model scope section answers: what is the attack class this decision is designed to resist, and what remains in-scope as accepted risk? Example: "This decision addresses server-side injection attacks and CSRF. It does not address client-side session theft (mitigated at the browser layer by HttpOnly cookie flags, addressed in ADR-0019) or supply chain attacks on npm dependencies (not in scope for this decision)."
  2. Data classification. What is the sensitivity level of the data this decision affects? Use whatever classification tiers your organization has defined (public, internal, confidential, restricted; or public, PII, PHI, payment data). If no organizational classification exists, define it in the ADR. Naming the data classification makes compliance scope questions answerable in thirty seconds rather than requiring a review of the full Context section to infer what kind of data is involved.
  3. Compliance scope. Which regulatory frameworks does this decision implicate, and does the decision expand or reduce the organization's scope under those frameworks? This field should be explicit about what it doesn't cover: if the team has reviewed the decision against GDPR and concluded it doesn't expand PHI scope, saying so creates an auditable record of that review, not just silence that an auditor might interpret as unawareness.
  4. Security reviewers. Who from outside the implementing team reviewed this decision before production deployment? This is the field auditors look for when they ask about the "four eyes principle" for security-sensitive changes. The reviewer should be named (not just "security team") with a link to their written sign-off — a GitHub PR review, a comment on the RFC document, or a dated email. If no external review occurred (which is common for early-stage startups), that should be explicitly stated, with a note on when external review will be introduced into the process. Honest gaps are better than silent ones.
  5. Review triggers. When should this decision be revisited, and what changes in the environment would require re-evaluation? Review triggers come in two forms: time-based ("review by 2027-Q2") and event-based ("review if service becomes externally accessible" or "review if we add a data processing agreement with a new third party"). Both can coexist in the same ADR. The time-based trigger handles the case where external conditions change and nobody notices; the event-based trigger handles the case where a known decision node arrives. At minimum, every security ADR should have one review trigger that would force it back into consideration when the threat model changes.

These five fields add roughly a paragraph each to the typical ADR. For a decision record that an auditor may review multiple years later, that overhead is trivially small relative to the value of having the record be self-contained and answerable without requiring the original author to be present.

The classification problem

Security ADRs have a structural tension that other ADR types don't: some of the information that makes them accurate and useful is also information that should not be in a public or broadly-accessible document. An ADR that documents "we do not validate X input parameter at the service layer because we rely on the API gateway to reject malformed requests" is operationally honest and important for future engineers to understand. It is also a statement about where a potential attack vector exists if the API gateway assumption ever breaks.

Two approaches handle this at different scales. For most engineering teams with small, trusted engineering organizations, the right approach is abstraction in the public ADR with a private operational record. The public ADR documents the decision at the class level: "Input validation is handled at the API gateway layer. Service-layer validation is scoped to business logic constraints, not security constraints. See SECURITY-RUNBOOK-007 for the operational specifics." The runbook lives in a private repository with access controls matching the team's data classification policy. Auditors get access to the runbook during the audit; the public ADR remains honest without being a roadmap.

For larger organizations with a dedicated security function, security ADRs may be designated as internal-only from creation — not in the engineering team's public ADR repository but in a security-controlled decision log with appropriate access controls. A public summary ADR can reference the internal record by ID: "See SECURITY-ADR-0042 (internal, security-team access) for the full decision record on access control architecture." This approach provides the audit trail without the exposure risk, and the ADR governance model for the organization can codify which decision types go to which repository.

The worst outcome is splitting the decision across both places without a clear link — public ADR that documents the positive framing without the accepted risks, private runbook that has the operational specifics but no connection back to the decision record. Auditors who find this pattern during preparation will ask which document is authoritative, and the honest answer ("neither, you have to read both") is the worst possible one. The link between the public summary and the private record should be explicit and bidirectional.

Compliance documentation as the primary value

For most engineering teams, the day-to-day value of a security ADR is the same as any ADR: future engineers understand why the system is built the way it is, and revisiting decisions doesn't require finding and interviewing the original author. But there is a secondary, episodic value that is orders of magnitude larger: the security ADR is compliance documentation.

SOC 2 audits ask whether security controls were deliberately designed and formally reviewed. The question isn't just "do you have encryption at rest?" — any auditor can check that by looking at the infrastructure configuration. The question is "what was the decision process for choosing this encryption approach, who reviewed it, and what alternatives were considered and rejected?" A security ADR answers this question in one document. The absence of such a record means reconstructing the decision in the audit room from memory, which is the most expensive and least reliable way to make the case that the decision was made thoughtfully.

GDPR compliance documentation follows the same pattern. Article 5's accountability principle requires organizations to be able to demonstrate compliance with GDPR principles — not just implement them. A decision record for every significant data processing choice (what data is stored, under which legal basis, for how long, with which processors) is the documentation layer that makes "demonstrating compliance" feasible. Without it, a data subject access request or a regulator inquiry requires the engineering team to reconstruct which decisions expanded what scope, when, and why — typically from code commits and whatever Slack threads survived the retention window.

The pattern is consistent: the value of compliance documentation is zero until the audit, and then it is extremely high. This is why security ADRs tend to be written after the compliance event rather than before it — the organizational motivation only arrives at the worst possible time. The quarterly decision review is the right structural intervention: it forces security decision documentation before the audit clock starts, as a regular cadence rather than a crisis response.

The review cadence requirement

Standard ADR lifecycle management treats most decisions as stable once Accepted, revisited only when explicitly superseded by a new decision. A security ADR that documents encryption choices from 2023 is not necessarily valid in 2026 — not because the decision was wrong at the time, but because the conditions that made it right may have changed without anyone having a mechanism to notice.

Four categories of change invalidate security ADR assumptions:

Review triggers don't require the team to redo the decision every time they fire. Most security ADRs will be re-reviewed and confirmed as still valid — the threat model hasn't changed, the compliance basis is still sound, the cryptographic choice is still current. The value of the trigger is the forced re-read: someone with current knowledge of the threat landscape and regulatory environment confirms that the decision's conditions haven't changed. When they have changed, the review trigger is what surfaces that before it becomes a liability.

What AI chat reveals about security decisions

Security decisions have disproportionately rich AI chat footprints. When engineers are working out security and compliance trade-offs, they tend to use AI chat as a research and thinking partner for longer than they do for purely technical decisions — because the domain is broader, less certain, and more dependent on interpreting regulatory language that isn't resolved by reading the code.

The specific sessions worth extracting for security decision recovery:

The startup in the opening scenario — going into SOC 2 prep without documented security decisions — typically finds that all of the material decisions are present in the founding engineer's AI chat history. The PII storage decision, the encryption choice, the access control architecture, the accepted risks — these were worked out in Claude or ChatGPT sessions that still exist in the export. Recovery protocol: export ChatGPT history and Claude conversations for each engineer who was involved in the early system design; run the extractor; look specifically for the compliance-research-pattern records (question shapes + regulatory terms + trade-off markers); write up the recovered reasoning as security ADRs with a note that the original decision was made contemporaneously but the formal record is being written retrospectively from recovered AI chat deliberation. Most SOC 2 auditors accept retrospective documentation when it can be corroborated by code commit dates and deployment history.

A security ADR template

The following template extends the standard Markdown ADR format with the five security-specific sections. All standard fields are preserved for compatibility with existing ADR tooling that parses by section heading:

# ADR-0019: Authentication — JWT with short-lived tokens, HttpOnly cookies for session state

**Date:** 2026-01-15
**Status:** Accepted
**Deciders:** Backend lead, mobile lead (reviewer)
**Security reviewer:** @securitylead — review on file at [link to PR comment]

## Context

The system needs to authenticate API requests from web and mobile clients. Options evaluated:
(1) Long-lived API keys with manual rotation, (2) OAuth 2.0 with third-party IdP,
(3) JWT with server-side validation and short-lived tokens, (4) Session cookies only.

## Decision

JWT with 15-minute access tokens and 7-day HttpOnly secure cookie for refresh state.
Server-side token invalidation via a deny-list in Redis (O(1) lookup per request).

## Consequences

Access tokens expire after 15 minutes, limiting the blast radius of token theft.
The Redis deny-list adds ~2ms per authenticated request (acceptable at current scale).
Mobile clients handle token refresh automatically via the refresh-token flow.
The deny-list grows unbounded until pruned; a scheduled job clears expired entries nightly.

## Threat model scope

**Addressed:** Session hijacking via XSS (mitigated by HttpOnly; JS cannot read the
refresh cookie). Token theft via network interception (mitigated by HTTPS-only
with HSTS; token lifetime limits blast radius). Replay attacks (mitigated by
deny-list invalidation on logout and token rotation on refresh).

**Accepted risk:** Compromised refresh token valid for up to 7 days if deny-list
is bypassed (e.g., Redis unavailable during outage — fail-open configuration).
Mitigation: fail-closed option documented in SECURITY-RUNBOOK-004 for future review.

**Out of scope:** Credential stuffing (handled at rate-limiting layer, ADR-0022).
Social engineering (out of technical scope).

## Data classification

Authentication tokens are classified as **Confidential** (internal). Refresh cookies
contain no PII; access tokens contain user ID and role claims only.

## Compliance scope

This decision does not expand GDPR personal data scope (user ID is a pseudonym;
role claims are internal system data). This decision satisfies SOC 2 CC6.1
(logical access controls) and CC6.3 (user identity management). No HIPAA scope.

## Security reviewers

- @securitylead: reviewed 2026-01-13, approved — [link to review comment]
- Architecture review board: reviewed 2026-01-14, no objections — [link to meeting notes]

## Review triggers

- **Time-based:** Review by 2027-Q1 for algorithm currency and library dependency audit.
- **Event-based:** Review if system expands to handle PHI (HIPAA scope implication).
- **Event-based:** Review if Redis is removed from the stack (deny-list assumption broken).
- **Event-based:** Review if any JWT library CVE is issued against our dependency version.

The accepted risk block in the Threat model scope section is the most practically important addition. It creates an explicit, readable statement of what the team accepted rather than requiring an auditor to infer accepted risks from absence of coverage. When the startup in the opening scenario recovers their original security decisions from AI chat, the accepted risk reasoning is almost always present — engineers naturally articulate what they're accepting in AI sessions, because that's the framing they use when working through trade-offs with an AI assistant. The recovery-to-ADR pipeline for this section is usually direct.

The compliance scope section should err toward over-specificity. Saying "no HIPAA scope" when the team has verified this is different from simply not mentioning HIPAA — the explicit statement creates an auditable record of review, not just an inference from silence. This distinction matters when the system's data handling expands in scope later: an ADR that explicitly says "no HIPAA scope as of 2026-01-15" combined with a later ADR that says "HIPAA scope added as of 2027-03-01" creates a clear timeline. An ADR that never mentioned HIPAA combined with a later ADR that adds HIPAA scope leaves a gap in the record that auditors will ask about.

Security ADRs and the quarterly review

The quarterly decision review is the right cadence for auditing the security ADR log for stale threat model assumptions and elapsed review triggers. Two questions identify security ADRs that need re-evaluation in the quarterly pass:

  1. "Has the threat model scope in this ADR's threat model section changed since the decision was made?" The most common signal: a decision that says "scope: internal services only" for a service that has since been exposed externally. If the threat model expansion was documented as a separate decision (as it should be), the link between the two ADRs surfaces the stale security ADR automatically. If it wasn't documented separately — which is why cross-cutting decisions need their own records — the quarterly review is the safety net.
  2. "Have any event-based triggers in this ADR fired since the last review?" Review triggers only work if someone checks them. The quarterly review is the check. A team that has documented good review triggers but never reads them has the same outcome as a team with no triggers at all.

Security ADRs promoted from AI chat recovery during the quarterly review should note their recovery provenance. This matters for audit purposes: "Decision made 2024-03-12, formal record written 2026-Q1 from recovered AI chat history (ChatGPT export sessions 2024-03-10 to 2024-03-14, confirmed by deployment timestamps in git history)" is an honest and defensible record. Auditors who understand how engineering actually works — which most do — accept this provenance. What they don't accept is a record written after an audit inquiry without any provenance statement at all.

Recover your security decision history before the audit call

The compliance research and threat-modeling deliberation that happened in AI chat sessions is the most complete record of why your security decisions were made. The WhyChose open-source extractor surfaces these from your ChatGPT and Claude exports — look for the compliance-research pattern (question shapes + regulatory terms + trade-off markers) and the pre-launch security review session cluster (high-confidence records concentrated in the date window before your first production deployment). Running the extractor before SOC 2 or GDPR documentation prep is substantially faster than reconstructing decisions from memory with an auditor on the call.

Join the waitlist for the hosted service — the Pro tier's cross-session linking connects scattered compliance research sessions to the same decision topic across months of chat history.

Further reading