Security incident-response runbook¶
The internal procedure for handling a vulnerability reported to
security@mudwoodlabs.com. The public-facing policy (where to report,
what to include, the response SLA) lives in
SECURITY.md; this runbook is the maintainer’s
checklist for what happens after a report lands.
Why this exists¶
pyrxd is a single-maintainer project handling cryptographic and
value-bearing code. Without a written procedure, response to a report is
ad-hoc and the SLA in SECURITY.md (acknowledge within 2 business days,
assess within 7, coordinate disclosure within ~90) is easy to miss under
pressure. This runbook makes the steps mechanical so the right things
happen in the right order, even for the first real report.
Severity guide¶
Use this to set urgency and the disclosure clock. When in doubt, round up.
Severity |
Examples |
Target fix window |
|---|---|---|
Critical |
Key/seed exfiltration; a forged SPV proof or REF that drains a Maker; signing the wrong tx; a covenant bypass that steals an in-flight swap |
Days; consider an out-of-band advisory |
High |
Fee/value miscalculation that loses funds; a broadcast-path crash that strands a confirmed commit; auth/confirmation-gate bypass |
~2 weeks |
Medium |
Information leak (key bytes in a traceback/log); a fail-open default where a control must be explicitly enabled |
Next scheduled release |
Low / Info |
Hardening gaps, missing warnings, defense-in-depth |
Backlog |
The trust boundaries and current accepted residuals are in
docs/threat-model.md — read the relevant scenario
(S1–S20) before assessing impact.
The flow¶
1. Acknowledge (≤ 2 business days)¶
Reply to the reporter from security@mudwoodlabs.com: confirm receipt,
give a tracking handle, and ask for anything missing (repro steps,
affected versions). Do not discuss the issue in a public channel,
issue, or PR.
2. Triage + reproduce (≤ 7 business days for the initial assessment)¶
Reproduce it. If you can’t, say so to the reporter and ask for more.
Set severity (table above) and the affected version range.
Open a private GitHub Security Advisory (Security tab → “Report a vulnerability” → draft):
gh api repos/MudwoodLabs/pyrxd/security-advisories -f summary=… -f severity=…. The advisory is the private workspace; it can request a CVE and spin a private fork for the fix when ready.
3. Fix privately¶
Branch from the advisory’s private fork (or a local branch you do not push to a public branch). Conventional-commit scope
fix(security):— but keep the message non-specific until disclosure.Write a regression test that fails before the fix (the project rule; for a value/assembly bug, a build→fee→sign or consensus-path test).
Run
task cilocally. Patch the lowest still-supported affected version if a backport is warranted (seeSECURITY.md→ Supported Versions).
4. Coordinate disclosure¶
Agree a disclosure date with the reporter (default ≤ 90 days, sooner for Critical). If the bug is being actively exploited, shorten it.
Request the CVE via the advisory if the issue warrants a public identifier (most Critical/High do).
5. Release the fix¶
Bump
pyproject.toml, updateCHANGELOG.md(crediting the reporter unless they opted out).Cut a GitHub Release → this triggers
.github/workflows/publish.yml(OIDC Trusted Publishing + PEP 740 attestations + the CycloneDX SBOM).Verify the new version is on PyPI with its provenance attestation.
6. Publish + notify¶
Publish the GitHub Security Advisory (this is the public disclosure).
Confirm to the reporter that it’s out; thank them.
If a config/usage change is needed by users, note it in the advisory and the release notes.
Update
docs/threat-model.md: close the gap or add the new scenario, and record any newly-accepted residual.
After-action¶
For anything Critical/High, write a short
docs/solutions/ note: the root cause, why existing tests
missed it, and the test class that now guards it — so the same class of
bug can’t recur silently.