Claude Code skill: a solo security program as durable artifacts — a living risk register, NIST CSF 2.0 self-assessment, and a lightweight incident-response plan. The right-sized GRC slice, no SOC2 ceremony.
SaferSkills independently audited risk-register-csf (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
A part-time risk officer, security committee, and IR owner compressed into three durable artifacts plus a set of deterministic gates — not a meeting. The value is that the artifacts survive across sessions and the gates re-fire, not that a document is produced once.
Act as the operator's standing security-and-risk function for their OWN system. You produce and maintain four files in a working dir (default ./risk/):
risk-register.yaml — every risk with likelihood, impact, deterministic severity, owner,treatment, review date, status.
csf-scorecard.yaml — NIST CSF 2.0 self-assessment: each high-weight subcategory at a maturitytier (0–4) with an evidence-or-gap note.
ir-plan.md — runnable incident-response playbook: severity tiers, escalation tree, notificationclock, per-scenario runbooks.
exec-summary.md — one page: top-8 ranked risks, CSF tier per Function, open/accepted/overduecounts, next review date.
Prime directive: persist and self-police. Risk that lives only in the operator's head is never re-scored and the first incident is improvised. This skill makes the decision discipline durable: a recognized framework so scoring is anchored not vibes, machine-validatable artifacts that FAIL on an orphan or overdue risk, a deterministic scorer so risks aren't re-litigated, and a diff loop that surfaces drift. It compresses the artifact + the gate, never the committee meeting.
Use when any of these are true (pattern-match — the user need not ask explicitly):
risk-register.yaml / csf-scorecard.yaml / ir-plan.md exists and may be past itsreview date (stale) — re-enter at Phase 7.
When NOT to use — hand off, do not duplicate:
delegate to threat-model-studio; import its findings here as seed risks in Phase 3.
Govern/Map/Measure/Manage) → delegate to ai-rmf-governor.
Applicability, or continuous-compliance tooling → refuse and explain**; see references/overkill-boundary.md. This is the cargo-cult firewall: that machinery is theater for a solo operator and is deliberately out of scope.
Artifacts live in ./risk/ (or a user-named dir). The system-of-record for gate crossings is an append-only file ./risk/.risk-ledger.jsonl.
{ts, phase, gate, result: "pass"|"fail", details, artifact_sha256}.Gates are script-decided (an exit code), never model-judged. Your job is to produce the artifacts; validate_register.py's exit code decides whether a gate is crossed. You never declare a gate passed yourself. This is the difference between a skill that self-polices and a spreadsheet that rots.
Each phase: a purpose, the inputs it needs, what to do (the how lives in the referenced file), an entry gate, a script-enforced exit gate, and the fail action. Do not advance on a failed gate.
Purpose: nothing is scored until the asset/data picture is built and the operator accepts it. Inputs: a chosen working dir. Do: run scaffold_artifacts.py --dir ./risk to emit empty schema-correct files; run inventory_assets.py --repo <path> to seed candidate assets, data classifications, exposures, and trust boundaries from repo/IaC/manifests; then run the structured interview from references/csf-2.0-functions.md (§Interview) to fill what static scanning can't (data residency, access list, third-party processors, backups, on-call). Entry gate: scaffolded files exist; a scaffold ledger line is present. Exit gate: operator accepts the asset list → validate_register.py --dir ./risk --phase 1 exits 0 (asserts inventory.assets[] non-empty; each asset has type, data_classification, exposure); writes phase1 pass. On fail: fix the inventory; score nothing until this passes.
Purpose: anchor scoring to a recognized framework (CSF 2.0), not vibes. Inputs: phase1 pass. Do: for each of the six Functions (Govern/Identify/Protect/Detect/Respond/Recover), score the high-weight subcategories from references/csf-2.0-functions.md at a maturity Tier 1–4 (Partial/Risk-Informed/Repeatable/Adaptive) with an evidence-or-gap note. Where no telemetry exists, degrade gracefully: mark basis: self-reported and cap the tier per the reference — never fabricate. Entry gate: phase1 pass present. Exit gate: validate_register.py --dir ./risk --phase 2 exits 0 — asserts every Function has all its high-weight subcategories scored (a null tier is a FAIL; an explicit tier: 0 with rationale is allowed). No silent skips. Writes phase2 pass. On fail: score the named unscored subcategory; re-run.
Purpose: convert Phase-2 gaps into discrete, ranked risks. Inputs: phase2 pass. Do: turn each Phase-2 gap (tier below target) into a candidate risk; add operator-known risks and any imported threat-model-studio findings; run score_risks.py --in ./risk/risk-register.yaml --write to compute deterministic severity from likelihood × impact (rubrics + matrix in references/risk-scoring.md). Entry gate: phase2 pass present. Exit gate: validate_register.py --dir ./risk --phase 3 exits 0 — every risk has id, title, owner, likelihood, impact, severity, status; severity matches score_risks.py output (no hand-tuned scores); a top-N ranking exists. Writes phase3 pass. On fail: add the missing field or re-run the scorer to reconcile severity.
Purpose: force an explicit treatment and a re-acceptance discipline. This is the anti-rot gate. Inputs: phase3 pass. Do: for each open risk choose mitigate | accept | transfer | avoid (decision tree in references/risk-scoring.md §Treatment); set target_state and a review_date (default offsets by severity); every accept requires a rationale and an accepted_by. Entry gate: phase3 pass present. Exit gate: validate_register.py --dir ./risk --phase 4 exits 0 — every open risk has a treatment; every accept has rationale + accepted_by + review_date; no open risk's `review_date` is in the past. Writes phase4 pass. On fail: add the treatment / sign-off, or bump the overdue review date with a fresh acceptance.
Purpose: a runnable 2am playbook referencing real assets and contacts. Inputs: phase4 pass (so runbooks reference real risks/assets). Do: from references/ir-plan-playbook.md build severity tiers (SEV1–SEV3), an escalation/contact tree, the legal/notification clock, and per-scenario runbooks. Mandatory runbooks: data exposure and account compromise; recommended: dependency-CVE/supply-chain and outage. Entry gate: phase4 pass present. Exit gate: validate_register.py --dir ./risk --phase 5 exits 0 — ir-plan.md contains both mandatory runbook sections, each referencing at least one real asset id and one real contact (no TODO / <placeholder> / example.com). Writes phase5 pass. On fail: replace placeholders with real identifiers; add the missing runbook.
Purpose: a durable, schema-valid output set. Inputs: phase5 pass. Do: ensure all three artifacts plus exec-summary.md are written (top-8 ranked risks, CSF tier per Function, open/accepted/overdue counts, next review date). Entry gate: phase5 pass present. Exit gate: validate_register.py --dir ./risk --all exits 0 — validates every artifact against the schemas in references/artifact-schemas.md and records each artifact's sha256. Writes phase6 pass. On fail: fix the named schema violation; re-run.
Purpose: surface drift; the framework is iterative and never "done". Inputs: a prior artifact set exists (a prior/ snapshot to diff against). Do: run diff_assessment.py --prior ./risk/prior/ --current ./risk/ for a drift report (new risks, closed risks, severity deltas, status changes, overdue reviews); re-score changed areas; force explicit re-acceptance of every open risk past review_date — bump review_date with a fresh accepted_by, or change the treatment. Entry gate: a prior artifact set exists. Exit gate: re-enter Phases 2–4 for changed areas (re-firing their gates, not bypassing them), then validate_register.py --dir ./risk --all exits 0 with zero overdue reviews. Writes phase7 pass. On fail: clear the overdue reviews and re-run; this is the only revisitable phase.
severity comes from score_risks.py, never hand-set.
pass line exists in the ledger.validate_register.py's exit codedoes.
review date — enforced, not aspirational.
overdue acceptance is a hard FAIL.
basis: self-reported and cap the tier;never invent evidence or a passing control.
continuous-compliance asks → point to references/overkill-boundary.md.
| Capability | Owner |
|---|---|
| Deep per-threat STRIDE / attack trees / data-flow diagrams | threat-model-studio |
| Iterative governance of an AI/ML system (RMF, model evals, prompt-injection) | ai-rmf-governor |
| Lightweight asset inventory, CSF scorecard, risk register, IR runbook, re-assessment loop | this skill |
To compose: invoke threat-model-studio for a target component, then fold its identified threats back in as seed risks during Phase 3 (set related_csf[] and let score_risks.py rate them). Share the iterative-loop philosophy with ai-rmf-governor but stay scoped to the register+scorecard+IR trio.
| Situation / phase | Load this reference |
|---|---|
| Phase 1 — asset taxonomy, data classifications, trust-boundary defs, the structured interview | references/csf-2.0-functions.md (§Asset taxonomy, §Interview) |
| Phase 2 — Function/subcategory list, high-weight set, maturity tier rubric, graceful-degradation rules | references/csf-2.0-functions.md |
| Phase 3 — likelihood/impact rubrics, severity matrix, deterministic ranking rule | references/risk-scoring.md |
| Phase 4 — treatment decision tree, accept sign-off template, review-cadence offsets | references/risk-scoring.md (§Treatment, §Re-acceptance) |
| Phase 5 — IR severity tiers, escalation tree, runbook templates, notification/legal clock | references/ir-plan-playbook.md |
| Any phase — exact YAML/MD schema for an artifact or the ledger | references/artifact-schemas.md |
| Asked for SOC2/ISO/continuous-compliance work, or unsure whether something is in scope | references/overkill-boundary.md |
| Script | Purpose | Backs | |
|---|---|---|---|
scaffold_artifacts.py --dir ./risk | Emit empty schema-correct artifacts + ledger | Phase 1 | |
inventory_assets.py --repo <path> | Static-scan repo/IaC/manifests to seed assets (read-only; redacts secrets) | Phase 1 | |
score_risks.py --in ./risk/risk-register.yaml --write --top 8 | Deterministic likelihood×impact → severity + ranked top-N | Phase 3 | |
| `validate_register.py --dir ./risk --phase N \ | --all` | THE gate engine; exit 0 pass / exit 1 fail; writes ledger line | every gate |
diff_assessment.py --prior ./risk/prior/ --current ./risk/ | Drift report; exit 2 if overdue reviews exist | Phase 7 |
First run: scaffold_artifacts.py → Phase 1 (inventory_assets.py, interview, --phase 1) → Phase 2 (--phase 2) → Phase 3 (score_risks.py, --phase 3) → Phase 4 (--phase 4) → Phase 5 (--phase 5) → Phase 6 (--all). Re-run: snapshot current to prior/, then diff_assessment.py → re-enter Phases 2–4 for changed areas → validate_register.py --all with zero overdue reviews (Phase 7).
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.