From 1813d9c0fd4d506ea44e4f23e3cf458cdf69f334 Mon Sep 17 00:00:00 2001 From: umpireboulianne-design Date: Sat, 24 Oct 2026 03:15:56 -0400 Subject: [PATCH] docs(security): publish vulnerability reporting and incident-response policy Fixes #476 --- README.md | 1 + SECURITY.md | 64 ++++++++++++++++++++++++++ scripts/check-security-policy.test.mjs | 33 +++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 SECURITY.md create mode 100644 scripts/check-security-policy.test.mjs diff --git a/README.md b/README.md index e4b4fb77..a4d89fc4 100644 --- a/README.md +++ b/README.md @@ -177,6 +177,7 @@ pnpm mainnet:verify # mainnet read-only proof | Doc | Purpose | | --- | --- | | **[ARCHITECTURE.md](./ARCHITECTURE.md)** | System overview, lifecycle, trust boundaries, repo map | +| **[SECURITY.md](./SECURITY.md)** | Supported versions, private vulnerability reporting, and incident response | | [docs/PLATFORM_PLAN.md](./docs/PLATFORM_PLAN.md) | Partner-ready protocol, SDK, template, and pilot delivery plan | | [docs/BUILD_PLAN.md](./docs/BUILD_PLAN.md) | Focused build/funding framing for sealed auction infrastructure | | [docs/GRANT_SUBMISSION.md](./docs/GRANT_SUBMISSION.md) | Grant submission narrative for the sealed auction product | diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..613a28ca --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,64 @@ + +# Security Policy + +This document defines the supported branches, private vulnerability reporting +process, and credential-compromise response checklist for the Sub Rosa +repository (`Sub-Rosa-Issue/sub-rosa-issue`). + +## Supported Versions + +Security fixes are applied to the `main` branch (`0.1.x` pre-release workspace +packages and Soroban contract primitive): + +| Component | Branch / Version | Supported | +| --- | --- | --- | +| `contracts/round` (Soroban primitive) | `main` (`0.1.x`) | Yes | +| `@sub-rosa/sdk` & `@sub-rosa/tlock` | `main` (`0.1.x`) | Yes | +| `services/keeper`, `services/appraisal-api`, `services/agent` | `main` (`0.1.x`) | Yes | +| `apps/web` | `main` (`0.1.x`) | Yes | +| Older commits / unmerged feature branches | `< main` | No | + +## Reporting a Vulnerability Privately + +**Do not open a public GitHub issue, pull request, or discussion** for +suspected security vulnerabilities, and **never post live Stellar secret seeds +(`S...`), private keys, RPC tokens, or unredacted environment files** in any +report. + +1. Use **[GitHub Private Vulnerability Reporting](https://github.com/Sub-Rosa-Issue/sub-rosa-issue/security/advisories/new)** + (`Security` → `Report a vulnerability` in this repository) to submit a + confidential advisory directly to the maintainers. +2. Include: + - Affected component(s) (`contracts/round`, `@sub-rosa/sdk`, `@sub-rosa/tlock`, `services/keeper`, etc.) and commit SHA. + - Minimal reproduction steps or a deterministic test fixture using generated throwaway keys (`Keypair.random()`). + - Impact assessment (e.g., escrow conservation, premature bid disclosure, signature verification, or keeper availability). +3. Maintainers acknowledge private reports within **72 hours**, coordinate a fix + in a private advisory branch, and publish a regression test once the fix is + merged. + +## Incident Response: Suspected Credential or Key Theft + +If a Stellar secret seed (`ADMIN_SECRET_KEY`, keeper/operator key, agent +mandate signer), GitHub token, or RPC credential is suspected of being exposed +or compromised, execute the following steps immediately: + +1. **Isolate:** + - Immediately stop affected keeper, appraisal-api, or agent processes. + - Disconnect the compromised workstation, container, or CI runner from + network access so no further signed transactions or API calls can be + originated from that host. +2. **Revoke:** + - Revoke exposed GitHub Personal Access Tokens, Actions secrets, and RPC + provider API keys. + - On Stellar, revoke or remove compromised signer weights / session-key + mandates on the affected account or contract configuration. +3. **Rotate from a clean machine:** + - Provision fresh Stellar keypairs and API credentials **only from a + verified clean machine** (never on the host where the leak occurred). + - Update deployment secrets and verify on-chain round and escrow invariants + with `pnpm mainnet:verify` and `pnpm mainnet:ready -- --strict`. +4. **Preserve evidence:** + - Before wiping or redeploying the affected system, preserve structured JSON + logs, shell history, CI run logs, and on-chain round receipts exported via + `@sub-rosa/receipt-cli` (`pnpm receipt:test` / `receipt-cli`) for post-incident + forensic review. diff --git a/scripts/check-security-policy.test.mjs b/scripts/check-security-policy.test.mjs new file mode 100644 index 00000000..dda8d0c4 --- /dev/null +++ b/scripts/check-security-policy.test.mjs @@ -0,0 +1,33 @@ +// Copyright (c) 2026 Sub Rosa contributors +import assert from "node:assert/strict"; +import { existsSync, readFileSync } from "node:fs"; +import { dirname, join, resolve } from "node:path"; +import { describe, it } from "node:test"; +import { fileURLToPath } from "node:url"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const REPO_ROOT = resolve(__dirname, ".."); + +describe("SECURITY.md policy", () => { + it("exists at the repository root and is linked from README.md", () => { + const securityPath = join(REPO_ROOT, "SECURITY.md"); + assert.equal(existsSync(securityPath), true, "SECURITY.md must exist at repo root"); + + const readme = readFileSync(join(REPO_ROOT, "README.md"), "utf8"); + assert.match(readme, /\[SECURITY\.md\]\(\.\/SECURITY\.md\)/); + }); + + it("documents supported versions, private reporting, and the 4-step credential compromise checklist", () => { + const security = readFileSync(join(REPO_ROOT, "SECURITY.md"), "utf8"); + assert.match(security, /## Supported Versions/); + assert.match(security, /`main`/); + assert.match(security, /## Reporting a Vulnerability Privately/); + assert.match(security, /security\/advisories\/new/); + for (const step of ["Isolate", "Revoke", "Rotate from a clean machine", "Preserve evidence"]) { + assert.ok( + security.includes(step), + `SECURITY.md must include incident response step: ${step}`, + ); + } + }); +});