trstctl /docs GitHub ↗

Vulnerability management

How trstctl receives, triages, fixes, and discloses security vulnerabilities. This is the process an enterprise vendor-risk review expects to find; it complements the reporting policy in SECURITY.md and the architectural threat model.

Coordinated disclosure

We practise coordinated disclosure. Reports arrive privately (GitHub private vulnerability reporting, or email to the maintainer — see SECURITY.md), we agree a remediation and disclosure timeline with the reporter, and we publish an advisory once a fix is available. We credit reporters who want to be credited and ask for a reasonable embargo while we remediate. We never penalise good-faith research conducted within the documented scope.

Triage

Every report is triaged on intake and assigned a severity that drives the SLA below.

  1. Acknowledge the report to the reporter and open a private tracking issue (a GitHub Security Advisory draft — GHSA).
  2. Reproduce against the latest main and the reported version/commit; capture a minimal proof of concept.
  3. Assess severity using CVSS v3.1 as the baseline, adjusted for trstctl's trust boundaries — anything that crosses a tenant boundary (AN-1), extracts or misuses key material (AN-3/AN-4/AN-8), forges or breaks the audit chain, or bypasses authentication/authorization is treated as at least High, and a remote, unauthenticated instance of any of those as Critical.
  4. Decide scope: confirm whether served subsystems are affected, identify the fix, and request a CVE ID (via GitHub) for anything Medium or above.
  5. Track the advisory through fix, release, and publication.

Patch SLA (by severity)

Targets are measured from triage confirmation. "Fix" means a patched main and, once releases are tagged, a patched release; "disclose" means publishing the advisory.

Severity Acknowledge Triage & assess Fix target Public disclosure
Critical 1 business day 2 business days 7 days with the fix (coordinated)
High 2 business days 3 business days 30 days with the fix
Medium 3 business days 5 business days 90 days with the fix or next release
Low 5 business days 10 business days best effort / next release next release notes

Critical issues may ship an out-of-band security release; lower severities are rolled into the normal release cadence. If a target will slip, we tell the reporter and agree a revised date rather than letting the embargo lapse silently.

Security releases & advisories

  • Fixes land on main first. A security release is tagged for Critical/High issues (and bundled for Medium/Low), with the cosign-signed, reproducible image and SBOM the normal pipeline produces.
  • We publish a GitHub Security Advisory (GHSA) with the CVE, affected versions/commits, severity, impact, remediation, and credit. The release notes link the GHSA.
  • Downstream forks and plugin authors can watch advisories; the conformance suites let them self-validate after pulling a fix.

Known dependency advisories (assessed not-reachable)

govulncheck runs in CI (reachability-aware) and fails the build on any advisory the code can actually reach. A small number of advisories exist in the dependency graph but are not reachable from trstctl's call graph; we record them here so a vendor-risk review sees a deliberate assessment, not an oversight. Each is re-checked on every dependency bump, and the upgrade that clears it is scheduled (not silently deferred).

Advisory Dependency Status Why not reachable Plan
GO-2025-3660 github.com/open-policy-agent/opa v0.69.0 Not reachable (govulncheck: not called) The advisory is a path-injection in OPA's server Data API. trstctl embeds OPA only as a library evaluator — it imports github.com/open-policy-agent/opa/rego and never .../server, so it does not run or expose the OPA HTTP server/Data API at all (internal/policy/policy.go). Upgrade to the OPA 1.x line (module path .../opa/v1) behind the policy-engine tests; tracked under SUPPLY-007. The 1.x bump is a major-version/module-path change, scheduled as its own dependency change rather than a hygiene-sweep edit.

If a future change ever wires OPA's server/Data API (it should not — trstctl evaluates Rego in-process), this advisory becomes reachable and govulncheck will fail CI until OPA is upgraded.

Triage dry-run (worked example)

A dry-run of the process end to end against a sample advisory, to prove the workflow holds before a real report arrives. (Illustrative — not a real vulnerability.)

Sample report: "An authenticated tenant A user can read tenant B's issued certificates by passing a crafted tenant_id to GET /api/v1/certificates."

  1. Acknowledge (day 0): reply to the reporter; open a private GHSA draft GHSA-xxxx-sample.
  2. Reproduce (day 0–1): stand up a two-tenant instance, issue a cert under tenant B, and confirm whether tenant A can read it. In this sample, suppose it reproduces.
  3. Assess: a cross-tenant read bypasses AN-1 row-level security — Critical (remote, authenticated, tenant-boundary crossing). CVSS ≈ 8.1. Request a CVE.
  4. Scope the fix: the offending handler trusted a request-supplied tenant_id instead of the authenticated context; the fix forces the tenant from the session and relies on the RLS policy. Add a regression: a projections integration test asserting tenant A receives 404/empty for tenant B's cert, plus a trstctllint check that the query path is tenant-filtered (AN-1).
  5. Fix (within the 7-day Critical target): patch main, tests green (make lint test), tag a security release.
  6. Disclose: publish GHSA-xxxx-sample with the CVE, affected commits, impact, the fixed version, and reporter credit; link it from the release notes.
  7. Retrospective: confirm the architecture linter or a new rule would have caught the class of bug, and file follow-ups if not.

This dry-run is re-run whenever the triage process or the served surface changes, so the process stays exercised rather than aspirational.

Rendered live from github.com/ctlplne/trstctl — found a mistake? edit this page.