On this page
Security
How CommonLayer handles security: what is verified before an artifact is published, how vulnerabilities are tracked after publication, how private reports and advisories work, and the documents that describe the platform's own security. Security status and maintenance status are tracked separately and never merged into one indicator.
| Page | Content |
|---|---|
| Verification policy | The 17 checks every artifact passes before promotion, waivers, project policies |
| Verifying artifacts | How consumers verify signatures, SBOMs and provenance themselves |
| Threat model | Assets, trust boundaries, threats, mitigations in code, open items |
| Privacy rules | What is public and what never is |
| Permission matrix | Generated from the code (clctl permissions): roles, permissions, token scopes, the human-only and never-by-token sets |
| Security review, November 2026 | An independent review of the backend on 2026-11-10: 19 findings (6 high, 7 medium, 6 low), all fixed with regression tests, and the areas it did not cover |
| Reporting a vulnerability in the platform | Disclosure process for CommonLayer itself |
Vulnerability management
The model (implemented in crates/commonlayer-security):
| Concept | Meaning |
|---|---|
| Vulnerability | One record per advisory, keyed by a canonical id (CVE preferred, then GHSA, then the source id), with aliases, severity, CVSS, EPSS and KEV status |
| Scan | One scanner run against one digest and platform |
| Occurrence | "This digest contains package P at version V, affected by X." Bound to one digest forever |
| Finding | "Project J has to deal with X." The unit of triage, deadlines, notifications and SLA |
| Assessment | An applicability statement with VEX semantics for a project or one digest |
| Exception | A documented, reviewed deviation from the remediation deadline |
A fix published under a new digest never changes an old digest. The old digest keeps
its occurrences and stays shown as affected. A finding is resolved when the current
digest of every supported version line has a fresh successful scan without the
vulnerability (or a not_affected statement covers it). When the last affected version
line reaches end of life, the finding closes as versions_eol.
Scanners and feeds
| Source | What it does | Cadence |
|---|---|---|
| Trivy (CLI) | Scans an image by digest | On submission, on publication, every 24 h for supported digests, manually |
| Grype (CLI) | Scans an image by digest | Same |
Project CI (scan.sh in each project) | Trivy and Grype on the image and on its CycloneDX SBOM, which includes the declared source-built components; both gate the release | Every build |
| OSV (HTTPS batch API) | Re-matches the components of stored SBOMs without pulling images | Every 6 h |
| EPSS, CISA KEV, OSV refresh, NVD (with an API key) | Enrich known vulnerabilities; KEV raises effective severity to at least high | Every 6 h |
Software built from source (nginx, Valkey, PostgreSQL, darkhttpd) is declared in the SBOM by the project; only Grype matches those declarations, Trivy does not (ADR-0039). A scanner whose binary is not configured is skipped and reported as such; at least one scanner must succeed for a scan to count as fresh. Raw reports are stored in object storage and treated as untrusted input. Freshness of scanners and feeds is exported as metrics and shown in the security centre. What was exercised for real: Trivy 0.76.2 and Grype 0.121.3 through the subprocess runner on a CommonLayer nginx image (WP-12), and both with real databases in the publish drill (WP-70g); the OSV, EPSS, KEV and NVD adapters were tested against recorded responses only, because the build sandbox's egress proxy cannot be used by the SSRF-safe client.
Deadlines and exceptions
Default deadlines (policy, not guarantees; per project in a versioned SLA policy): critical 24 h / 7 days, high 48 h / 14 days, medium 7 days / 30 days, low 14 days / end of the next calendar month. The policy in force is snapshotted on each finding. Breaches are permanent (ADR-0029). Maintainers' duties around findings are described in the maintainer handbook.
Exceptions (no_upstream_fix, not_applicable, alternative_mitigation,
coordinated_disclosure, external_dependency, risk_accepted) need a justification, an
expiry and a new remediation date, and are decided by someone other than the requester.
They are public with their justification unless embargoed. On expiry the finding returns
to open.
Second reviewer. A not_affected assessment or imported VEX statement about a finding
whose effective severity is at or above security.not_affected_confirmation_min_severity
(runtime setting, default high) is pending until a second person with triage rights
confirms it; the author never can. While pending it covers nothing: deadlines run, the scan
gate blocks, nothing is published
(ADR-0037).
OpenVEX documents can be imported per project (POST /api/v1/projects/{slug}/vex) and are
exported per project and per digest (GET …/vex).
Advisories, private reports and incidents
- Advisories (
CLSA-YYYY-NNNN, numbered on publication, gapless per year) are written by a project's security roles and published to the security centre, an Atom feed (GET /api/v1/security/advisories.atom) and notifications. - Private reports: any signed-in user can report a suspected vulnerability in a
project privately (
POST /api/v1/security/reports, at most 10 per user per day). Bodies and messages are encrypted at rest withSecretBox, never logged, and visible only to the reporter, holders ofproject.security.read_privateon that project, and holders ofplatform.security.manage. States:submitted → triaging → accepted | rejected | duplicate → fixed → disclosed. An accepted report can create an embargoed finding; disclosure is an explicit, audited step. - Incidents are platform-level security incidents with a timeline, managed by
platform.security.manage, optionally public.
Vulnerabilities in the CommonLayer platform itself are reported through the process in SECURITY.md, not through the project report form.
Platform security controls
The controls that protect the platform itself (sessions, CSRF, rate limits, webhook signatures, the SSRF-safe client, subprocess isolation, database-enforced invariants, encryption of private data, audit log) are listed with their code locations in the threat model, together with the open items that still need work.