Skip to content

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-level security-incident-policy.md are 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

  1. Create the internal entry first. Append to internal/findings.md with the next free SR-NNN ID. Fill every internal field (CVSS, file:line, repro, PoC, owner). If a field is unknown, use {{TBD}}do not fabricate.
  2. Derive the client entry. Add a row to client/risk-register.md with the same SR-NNN. Severity, status, and planned-remediation must match. Strip everything else to business language.
  3. Sanitization grep. Before committing, run:
    grep -nE '(\.ts:[0-9]+|line [0-9]+|exploit|PoC|proof of concept|repro)' docs/security/client/ docs/security/security-incident-policy.md
    
    The output must be empty.
  4. Versioning. Both files participate in the doc-version system maintained by the sibling doc-versioning-author agent — bump the doc version on substantive changes; severity/status changes require a version bump.
  5. Closing a finding. Move the entry's status to Mitigated in 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.

  • Per-finding deep-dives: docs/security-findings/sf-NNN-*.md (legacy; being folded into internal/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 of internal/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.