Control-level audit readiness for SOC 2, ISO/IEC 27001:2022 and NIST SP 800-53 Rev. 5 / FedRAMP. Scope the audit (criteria or baseline, systems, period, Type 1 vs Type 2), build the control inventory, write an evidence request per control (artifact, owner, sample, test method), test what the repo and configs show (CC8.1 / A.8.32 / CM-3 change management via branch protection), hand technical checks to the owning skill, and record control gaps in the shared findings format with a control matrix. Use when the user mentions 'SOC 2,' 'SOC 2 Type 2,' 'Trust Services Criteria,' 'ISO 27001,' 'ISMS,' 'Statement of Applicability,' 'Annex A controls,' 'NIST 800-53,' 'FedRAMP,' 'FedRAMP 20x,' 'SSP,' 'POA&M,' 'control matrix,' 'evidence request list,' 'PBC list,' 'audit readiness,' 'control testing,' or is getting ready for an external auditor or assessor.
96%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
Get a control set ready for an external auditor: decide what's in scope, list the controls, write the evidence request an auditor would send for each one, test what you can from the repo and exported configs, and record what's missing or failing. The result is a control matrix, an evidence-request list, and a findings.json of control gaps that rates each gap by the exposure it leaves, not by how an auditor might word the opinion.
This is the program-level layer. It doesn't re-run technical audits: when a control's evidence is a technical check (branch protection, MFA enforcement, encryption at rest), it hands the check to the skill that owns it and folds the result back in.
Cross-references: csf-mapping (crosswalk a control set to NIST CSF 2.0, and governance-level gap analysis), pci-audit and hipaa-audit (code-facing audits when the in-scope data is cardholder data or PHI), iam-audit (access reviews, MFA, joiner/mover/leaver evidence), cloud-audit (logging, encryption, network and backup settings), secrets-audit, dependency-audit and container-audit (vulnerability management evidence), siem-detection (monitoring and alerting evidence), incident-triage (incident response plan and test evidence), privacy-engineering (SOC 2 Privacy category), finding-triage (dispositions after the audit), security-comms (readiness updates for executives and the board).
Input: the framework and criteria in scope, the system description or boundary, the audit period, and whatever evidence the user can share (policies, ticket exports, config exports, the repo).
Not for: NIST CSF 2.0 tiers, profiles or a board roadmap → csf-mapping. Card-data code and scope review → pci-audit. PHI flows and Security Rule safeguards in code → hipaa-audit. AI governance against the NIST AI RMF → ai-risk-management. GDPR / CCPA implementation → privacy-engineering. Triage of one scanner finding → finding-triage. The technical checks themselves → the skill named in the handoff table below.
scope.md, control-matrix.md, evidence-requests.md, findings.json, evidence/).gh api for branch protection, an IdP or cloud CLI listing). Use the user's own credentials and read-only calls only. Never change a setting during the audit; a fix made mid-period is recorded as remediation with its date.Write scope.md before anything else. Most readiness work that goes wrong went wrong here.
| Decision | What to pin down |
|---|---|
| Framework and version | See the framework table below. Name the version in the report header |
| Criteria or baseline | SOC 2: Security (the common criteria) is always in; add Availability, Confidentiality, Processing Integrity, Privacy only where customers or contracts need them. ISO 27001: all of clauses 4–10, plus the Annex A controls the Statement of Applicability includes. 800-53: the 800-53B baseline from the FIPS 199 categorization (Low / Moderate / High, plus privacy), tailored; FedRAMP: the Rev5 baseline or the 20x class being pursued |
| System boundary | The service, its infrastructure, software, people, procedures and data. List every in-scope system by name |
| Third parties | Subservice organizations (cloud host, IdP, payroll) and whether each is carved out or included; the complementary controls you rely on them for, and the ones your customers must run (CUECs) |
| Audit period | SOC 2 Type 1: a single date (design only). Type 2: a period, commonly 3 to 12 months (design and operating effectiveness); a first Type 2 is often 3 to 6 months. ISO 27001: Stage 1 then Stage 2, with records showing the ISMS has run (an internal audit and a management review at least), then yearly surveillance. 800-53 / FedRAMP: an initial assessment, then continuous monitoring (monthly scans, annual assessment) |
| What exists already | Prior reports, an existing control matrix, policies, a GRC tool export. Start from the organization's controls, not a blank list |
Frameworks this skill carries a reference for:
| Framework | Reference | Version to assess against |
|---|---|---|
| SOC 2 | references/soc2.md | AICPA 2017 Trust Services Criteria with the 2022 revised points of focus |
| ISO/IEC 27001 | references/iso27001.md | ISO/IEC 27001:2022 with Amendment 1:2024; the 2013 transition ended 31 October 2025. Build the inventory from the Statement of Applicability |
| NIST SP 800-53 / FedRAMP | references/nist-800-53.md | SP 800-53 Rev. 5 Release 5.2.0 (August 2025) with 800-53B baselines; FedRAMP Rev5 baselines or 20x Key Security Indicators under the Consolidated Rules for 2026 (mandatory 1 January 2027). FedRAMP rules are moving fast: check fedramp.gov first. Build the inventory from the SSP |
For a crosswalk between frameworks, or to NIST CSF 2.0, map each control here to its CSF subcategory with csf-mapping and keep the mapping in a csf column of the control matrix. One control, evidenced once, can satisfy several frameworks; say which.
One row per control the organization operates, not per criterion. A criterion is usually met by several controls, and one control often serves several criteria.
| Field | Example |
|---|---|
| Control ID | CHG-02 (the organization's own ID) |
| Framework refs | CC8.1, A.8.32, CM-3 |
| Control as operated | "Every merge to main needs one approving review from someone other than the author; CI must pass" |
| Owner | Role, not a person's name: "Engineering manager, platform" |
| Frequency | Per event / daily / weekly / monthly / quarterly / annual |
| Type | Manual or automated; preventive or detective |
| Systems | Which in-scope systems it runs on |
| Design status | Designed / partially designed / not designed |
A criterion with no mapped control is a design gap. Record it in Step 5.
Write each control as something a tester can check. "We follow least privilege" can't be tested; "Quarterly, the system owner reviews production database access against the HR roster and removes leavers within 2 business days" can.
For each control, write the request the auditor will send, before they send it. Put them in evidence-requests.md, one row per request.
| Field | What to write |
|---|---|
| Request ID | ER-CHG-02-1 |
| Control | CHG-02 |
| Artifact | Exactly what to produce: "export of merged PRs to main in the period, with reviewer and CI status" |
| From whom | The role or system that holds it |
| Population and period | The full list the sample is drawn from, and its dates. Type 1: as of the report date. Type 2: the whole period |
| Sample | Size by control frequency (table below). The tester picks the sample, not the control owner |
| Test method | Inquiry / observation / inspection / reperformance (below) |
| Pass condition | What a sample must show to pass: "approver ≠ author, approval before merge, CI green at merge" |
Test methods, weakest to strongest. Inquiry alone never evidences a control; pair it with at least one of the others.
| Method | What it is | Example |
|---|---|---|
| Inquiry | Ask the owner how it works | Interview the on-call lead about alert handling |
| Observation | Watch it happen | Watch a new hire's account being provisioned |
| Inspection | Examine a record or config | Read the access-review ticket, the branch protection export |
| Reperformance | Redo the control independently and compare | Re-run the leaver check: compare the HR termination list to active IdP accounts |
Sample sizes for Type 2. Typical auditor practice (firms differ; ask yours):
| Control frequency | Typical sample |
|---|---|
| Annual | 1 |
| Quarterly | 2 |
| Monthly | 2 to 5 |
| Weekly | 5 to 15 |
| Daily | 20 to 40 |
| Many times a day, or per event (PRs, tickets, hires) | 25 to 60, or a percentage of the population |
| Automated, configured once | 1 test of the configuration, plus evidence it didn't change in the period (change history) |
The SOC 2 reference lists the usual artifacts per criterion.
Test read-only, and only what the repo or a saved export actually shows. Everything you test becomes evidence under <audit dir>/evidence/, saved redacted and pretty-printed so line numbers stay put, with the command and time in the record's description.
What the repo can usually evidence directly:
| Control area | Where to look | Example check |
|---|---|---|
| Change management | Branch protection, CODEOWNERS, CI workflows, PR history | gh api repos/<owner>/<repo>/branches/main/protection (read-only, with the user's go-ahead); rg -n "required_approving_review_count|enforce_admins" -g '*.tf'; portable: `grep -rnE "required_approving_review_count |
| Infrastructure as code | Terraform, CloudFormation, Pulumi | Encryption, logging and backup settings on in-scope resources |
| Vulnerability management | Dependabot or Renovate config, scanner workflows | ls .github/dependabot.yml renovate.json 2>/dev/null; required scan jobs in CI |
| Secrets handling | Secret scanning config, .gitignore, env templates | Pre-commit or CI secret scanning present and required |
| Logging | App logger config, retention in IaC | Retention period vs the policy's stated period |
| Policies in the repo | docs/, SECURITY.md, policies/ | Approval and review dates, owner named |
Hand the technical depth to the owning skill and fold its verdict back into the control row. Don't redo its work here.
| Control area | Owning skill | What comes back |
|---|---|---|
| Access provisioning, reviews, MFA, leavers | iam-audit | IdP policy findings, orphaned accounts |
| Cloud logging, encryption, network, backups | cloud-audit | Resource-level findings and evidence files |
| Vulnerability and patch management | dependency-audit, container-audit, patch-sweep | Open advisories and their age vs the SLA in policy |
| Secrets management | secrets-audit | Committed or live credentials |
| Secure development | owasp-audit, api-audit | Application findings for the SDLC control |
| Monitoring and alerting | siem-detection | Detection coverage for the monitoring control |
| Incident response | incident-triage | Plan, tabletop or real-incident records |
| Cardholder data or PHI in scope | pci-audit, hipaa-audit | Framework-specific technical findings |
A handed-off finding keeps its own fingerprint and skill. In the control matrix, cite its fingerprint against the control it affects instead of writing a second record for the same root cause.
What the repo can't show (HR records, training completion, vendor reviews, board minutes, the access review itself) goes in the evidence-request list for the owner.
Close every candidate gap with one verdict, as defined in references/findings-format.md, and run the refutation pass in references/verification.md before anything is confirmed.
A control that's missing or failing is a finding; the control is the intended control. Rate severity by the exposure the gap leaves, using references/severity-calibration.md, not by audit-opinion risk. "This would be a qualified opinion" is not a severity. A leaver with live production database access 40 days after termination is High because of what that access reaches. A quarterly review that ran 10 days late, with nothing wrong found when it did run, is not an exposure.
Documentation gaps are not findings. A policy that's missing, unsigned or a year past review, an overdue training record, a vendor review not filed, a control description that doesn't match practice: list them in the report's "Documentation gaps (not findings)" section with the criterion, owner and the evidence expected. No severity, no findings.json record. They still matter to the auditor, and the report says so. Defense-in-depth gaps where another control already covers the exposure are hardening notes.
Design gaps vs operating exceptions: a control that doesn't exist (design) and a control that exists but failed in a sample (operating) are both findings if they leave an exposure. Put which one in ext.gap_type.
What each verdict looks like here:
confirmed: evidence you read shows the control missing or failing, and what that exposes.
main on the production repo shows no required reviews and enforce_admins: false, and the deploy workflow ships every push to main to production. Trace: push access (entrypoint) → unprotected main (propagation) → production deploy job (sink), all pointing at the evidence file and the workflow file. Medium or High depending on who holds push access and what production holds.test_method: reperformance.needs_validation: the evidence that decides it lives with a person or a system you can't read. The blocker is that fact, and the validation plan is the evidence request.
rejected: evidence shows the control designed and operating, so the gap claim is ruled out. ruled_out_by.location points at that evidence.
enforce_admins: true, and a sample of 25 merged PRs from the period all show an approver other than the author.Location. Every record needs a location. Point it at the strongest artifact you read: the repo file, or the saved evidence file and the line of the decisive field. When nothing is readable yet (a needs_validation that waits on a person), point it at that request's line in <audit dir>/evidence-requests.md.
Fingerprints are control-audit/<framework>/<control id>/<system or scope>, slash-separated, lowercase framework slug, no line numbers. Use the framework's own ID for the control; write enhancement or sub-item parentheses with a dot (AC-2(1) → AC-2.1), since parentheses aren't allowed in fingerprints. Name the system or scope so the same control on two systems gets two records:
control-audit/soc2/CC6.2/okta-workforce
control-audit/soc2/CC8.1/github/acme/api
control-audit/soc2/A1.2/aws/123456789012/prod-db
control-audit/iso27001/A.5.18/okta-workforce
control-audit/fedramp/SC-28.1/aws/123456789012/prod-dbFramework slugs: soc2, iso27001, nist80053, fedramp.
ext fields (flat, snake_case; don't repeat anything that already has a field):
| Key | Value | Example |
|---|---|---|
framework | Framework and version | "soc2-tsc-2017", "iso27001-2022", "nist-800-53r5-5.2.0", "fedramp-rev5-moderate" |
control_id | The framework control or criterion | "CC6.2", "A.8.32", "clause-9.2", "AC-2.3" |
responsibility | 800-53 / FedRAMP: who implements it | "system", "inherited", "hybrid", "customer" |
poam_id | 800-53 / FedRAMP: the POA&M row tracking it, if any | "V-0142" |
org_control_id | The organization's own control ID, if any | "IAM-04" |
test_method | How it was tested | "inspection", "reperformance" |
evidence_request | The request ID that holds or would hold the evidence | "ER-IAM-03-1" |
gap_type | "design" or "operating" | "operating" |
sample | Exceptions over sample size, when sampled | "3/25" |
csf | NIST CSF 2.0 subcategory, from csf-mapping | "PR.AA-05" |
Then:
findings.json sorted by fingerprint, with skill: "control-audit". Validate it and fix every error: node references/validate-findings.mjs findings.json (references/validate-findings.mjs). Optionally export SARIF: node references/to-sarif.mjs findings.json -o findings.sarif (references/to-sarif.mjs).notes.md next to the JSON. They are not records.findings.json and match by fingerprint. A rejected record stays rejected unless the evidence behind it is from an earlier period; a new period means new samples.Dispositions (set later, usually by finding-triage): Fixed / Deferred / Accepted Risk / Mitigated (platform/config) / Requires major migration. For an audit, "Fixed" needs the date: a fix late in a Type 2 period still leaves the exception in the period.
Write findings.json first. Render the report from it; the prose never changes a verdict, severity or blocker the JSON doesn't already say.
# [Framework] Audit Readiness Review
## Organization: [name] ## System: [name / boundary] ## Framework: [name + version]
## Criteria or baseline: [e.g. Security + Availability] ## Report type: [Type 1 as of date | Type 2, period start–end]
## Date: [date] ## Reviewer: [name] ## Scope: [full | partial, what was left out]
## findings.json: [path], validated: [yes] ## Evidence folder: [path]
### Summary
- Controls in scope: [N] Evidenced: [n] Gaps (findings): [n] Awaiting evidence: [n] Documentation gaps: [n]
- Confirmed: [N] (Critical [n] | High [n] | Medium [n] | Low [n]) Needs validation: [N] Rejected: [N]
- Readiness call: [ready for fieldwork | ready after the items below | not ready], one line on why
### Control matrix
| Org control | Framework refs | Owner | Frequency | Test method | Evidence request | Status | Record / note | CSF |
|---|---|---|---|---|---|---|---|---|
| CHG-02 | CC8.1 | Eng manager | Per PR | Inspection, 25 samples | ER-CHG-02-1 | Gap | `control-audit/soc2/CC8.1/github/acme/api` | PR.PS-01 |
Status: Evidenced / Gap / Awaiting evidence / Documentation gap / Not applicable (with reason).
### Evidence-request list
| Request | Control | Artifact | From | Population and period | Sample | Test method | Pass condition | Status |
|---|---|---|---|---|---|---|---|---|
### Confirmed findings
#### [SEVERITY] [Title] `fingerprint`
**Control:** [ext.control_id] / [ext.org_control_id] **Gap type:** [design | operating] **Sample:** [ext.sample]
**Location:** `path:line` (repo or evidence file) **Confidence:** [medium | high (reproduced)] **Test:** [ext.test_method]
**What and why it matters:** [the evidence and the exposure it leaves]
**Fix:** [concrete change, and the evidence that will show it operating]
**Verify the fix:** [the test the auditor will run]
### Needs validation
| Finding | Control | Blocker | Evidence request (validation plan) |
|---|---|---|---|
### Documentation gaps (not findings)
| Criterion | What's missing | Owner | Evidence expected | Due before |
|---|---|---|---|---|
### Hardening notes (not findings)
- [gap] — [why it isn't a finding] — [effort]
### Rejected (do not re-raise)
| Fingerprint | Ruled out by | Location |
|---|---|---|
### Handed off
| Control | Skill | Record or status |
|---|---|---|
### Third parties and complementary controls
| Subservice org | Carve-out / inclusive | Their report on file (type, period) | Complementary controls we run |
|---|---|---|---|
### Prioritized remediation plan
1. [highest exposure first; then anything that must operate for the whole period, since it has to start now]The control matrix counts records from findings.json and entries from the documentation-gap list. It is not a separate judgement.
ext.poam_idincident-triage if it looks usedaicpa-cima.comiso.org (copyrighted; the reference file paraphrases control titles)csrc.nist.gov, pages.nist.gov/OSCALfedramp.govreferences/ at build time): references/findings-format.md, references/verification.md, references/severity-calibration.md, references/findings.schema.jsonbriiirussell/cybersecurity-skills
c79bb8b
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.