Security documentation — track entrypoint¶
Banner. Internal-only documents are explicitly marked with a 🔒 banner at the top of each file. Documents under
client/and the root-levelsecurity-incident-policy.mdare pre-sanitized for sharing with customers, auditors, and external partners.Quick references: Glossary — terminology · FAQ — common questions · Service catalog — operator inventory · Portal audit — verification report · Inventory — every doc in the portal.
This directory replaces the legacy single-file docs/security-register.md (now a redirect) with a two-layer model: one layer that is safe to hand to a customer or partner, and one layer that contains the operational details engineering needs to remediate.
Why two layers¶
The previous register mixed customer-grade severity ratings with file:line citations, repro steps, and seed-leak details. Sharing the register externally meant either redacting it manually each time (error-prone) or refusing to share it (unhelpful). The split forces a disciplined boundary: every customer-facing entry has an internal counterpart, and the internal counterpart never leaks back into the customer track.
Layout¶
docs/security/
├── README.md ← you are here
├── security-incident-policy.md ← CUSTOMER-SHAREABLE: high-level IR flow
├── client/ ← CUSTOMER-SHAREABLE
│ └── risk-register.md ← sanitized severity + status table
└── internal/ ← 🔒 INTERNAL ONLY
├── findings.md ← full findings: code refs, repro, PoC
├── dependency-audit.md ← npm/pnpm audit output, top deps
├── threat-model.md ← STRIDE walkthrough
└── incident-history.md ← past incidents + post-mortems
Client layer (client/ + root runbook)¶
Audience: customers, partners, prospective auditors under NDA, sales conversations. Contents:
- Severity rating per finding (Critical / High / Medium / Low) — CVSS v3.1 where assignable.
- Affected component at a coarse level (e.g. auth subsystem, admin panel) — never a file path or line number.
- Status (Mitigated / In Progress / Accepted / Wontfix) and planned remediation date.
- Customer-impact statement in business language (1–2 lines).
Hard exclusions in the client layer: file paths, line numbers, function/class names, repro steps, exploit chains, PoC code, secret names, environment-variable names, vendor-specific advisory URLs that fingerprint our exact versions.
Internal layer (internal/)¶
Audience: engineering, SRE, security on-call. Contents:
- Everything from the client layer plus:
- Exact file paths and line numbers in source.
- CVSS vector + score, CWE / CVE mapping.
- Reproduction steps (curl, harness, manual).
- Proof-of-concept — code snippet, payload, or attack chain.
- Owner (engineer assigned) + due date.
- Verification recipe (how to confirm the fix landed in CI, in staging, in prod).
- Vendor-advisory cross-references and any internal Slack threads / postmortem links.
Severity rubric¶
Same scale across both layers — only the supporting detail differs.
| Sev | Definition | Customer-impact phrasing |
|---|---|---|
| Critical | Exploitable without authentication, data loss, or financial loss | "Can be triggered without login; affects funds or fairness" |
| High | Authenticated exploit, privilege escalation, silent data corruption | "Requires a valid account but breaches authorization" |
| Medium | Information disclosure, enumeration, denial-of-service | "Leaks limited information or degrades a single feature" |
| Low | Hardening, hygiene, performance, maintainability | "Defense-in-depth; no immediate user-visible impact" |
Workflow — adding a new finding¶
- Create the internal entry first. Append to
internal/findings.mdwith the next freeSR-NNNID. Fill every internal field (CVSS, file:line, repro, PoC, owner). If a field is unknown, use{{TBD}}— do not fabricate. - Derive the client entry. Add a row to
client/risk-register.mdwith the sameSR-NNN. Severity, status, and planned-remediation must match. Strip everything else to business language. - Sanitization grep. Before committing, run: The output must be empty.
- Versioning. Both files participate in the doc-version system maintained by the sibling
doc-versioning-authoragent — bump the doc version on substantive changes; severity/status changes require a version bump. - Closing a finding. Move the entry's status to
Mitigatedin both layers. Internal layer additionally records the verification PR + the CI assertion that pins the fix.
Mapping to historical IDs¶
The old register used three prefixes: SF- (security findings), FM- (flow-mode failures), AF- (architectural). The new layer uses a unified SR-NNN series in the client register; the internal findings.md keeps the legacy ID in parentheses so existing E2E tests and PR comments still resolve. A cross-reference table at the bottom of internal/findings.md is authoritative.
Related tracks¶
- Per-finding deep-dives:
docs/security-findings/sf-NNN-*.md(legacy; being folded intointernal/findings.md). - Flow docs with security commentary:
docs/flows/*.md§6. - Architecture security overview:
docs/weaknesses-register.md. - Performance / DoS surfaces:
docs/perf-*series — overlap with the "Denial of service" bucket ofinternal/threat-model.md.
Versioning¶
Both layers are tracked under the doc-version system. Substantive changes (new finding, status flip, severity change) require a version bump; cosmetic edits (typo, formatting) do not.