Stratify
Legal and compliance

Internal Audit Programme & Procedure

docs/compliance/isms/governance/GOV-11-internal-audit.md

Source updated 03. Aug. 2026

Internal Audit Programme & Procedure

Satisfies ISO/IEC 27001:2022 clause 9.2. No internal audit has been run yet. This document establishes the programme and procedure for the first one — it is not a report on a cycle that already happened, and nothing below should be read as implying otherwise.

Purpose

An internal audit checks whether the ISMS's own claims about itself are true: whether a control recorded as implemented in register/controls.yaml actually still is, whether a document marked approved was genuinely reviewed, and whether stated procedures are being followed in practice rather than just written down. It is the mechanism that keeps the register honest over time, as distinct from the Phase 0 gap analysis that produced the register's current state.

Scope

The audit programme's scope is the full Annex A control set in register/controls.yaml (93 controls, of which 90 are applicable to stratify's ISMS scope — see GOV-01 and GOV-06). A single audit cycle need not re-verify every control from scratch; see prioritization below.

Procedure

  1. Scope selection. For the first cycle, scope is the full applicable control set, since no

prior audit exists to narrow against. For subsequent cycles, scope is prioritized rather than exhaustive (see below), with a note of what was excluded and why.

  1. Prioritization. Two categories get checked first, in order:
  • Controls currently marked implemented (5 as of 1 August 2026: 5.15, 5.34, 8.3, 8.10, 8.28) —

these carry the highest reputational cost if the claim turns out to be stale, and are the cheapest to verify since each cites a specific, checkable artifact (a migration file, a code path, a CI job).

  • Any control whose status has changed since the previous audit cycle (or, for the first

cycle, since the Phase 0 gap analysis) — a status change is exactly the kind of claim an audit exists to test. Controls that have sat at not_started unchanged carry lower audit priority — there is little to verify about a control nobody has claimed progress on.

  1. Evidence sampling. For each control in scope, the auditor re-checks the citation the

justification field points to against the current state of the repository — not against memory of what the justification said. Example: control 8.3 (Information access restriction, status implemented) cites RLS enforcement on ≥23 tables; verifying it means re-running the grep across supabase/migrations/*.sql that register/facts.md describes, not accepting the prior write-up at face value.

  1. Findings. Any control where the claimed status no longer matches the evidence — better or

worse — is recorded as a finding. A downgrade (e.g. implementedpartial because a policy that was cited no longer exists) is recorded as a nonconformity in GOV-13, following that document's root-cause / corrective-action process. An upgrade is recorded as a register/controls.yaml update with a note of what changed.

  1. Reporting. Findings are summarized and carried into the next

GOV-12 management review as an input, alongside the raw nonconformity log entries.

Cadence

Proposed: annual, full applicable Annex A set as scope, using the prioritization above rather than a flat re-check of all 93 controls every time. The first cycle should be scheduled once the Tier 0 governance document set (this document included) reaches approved status — auditing an ISMS against documents that are themselves still drafts produces findings that are really just "the draft isn't approved yet," which isn't useful signal.

A known limitation of a solo-team internal audit

ISO 27001's independence expectation for internal audit is that the auditor doesn't audit their own work. On a team where Toby is both the ISMS Owner who implements controls and the only person available to audit them, that independence does not exist — the same person who wrote the RLS policy is the one checking that it's still enforced. This is stated here as a known, structural limitation, not something this procedure pretends to solve.

The mitigation available today is not independence but rigor: every audit finding must be citation-grounded against the actual repository state (a file, a migration, a CI run) rather than self-assessed from memory or intent. "I believe this still works" is not an audit finding; "line 19 of 0002_rls.sql still has this policy, verified 2027-MM-DD" is. Where a finding touches privacy or GDPR/revDSG-adjacent controls specifically, Antonios (DPO / Privacy Owner) reviewing the finding before it's closed is a reasonable informal second pair of eyes, even though it does not amount to formal audit independence. A genuine second technical reviewer, once one joins the team, should take over some or all of the control-verification work — this is the same trigger condition named in GOV-08 objective 7 for segregation of duties generally.

Records

Each audit cycle should produce a dated record: scope, controls checked, findings (if any), and what was carried into GOV-13 and the next management review. No such record exists yet, since no audit has run.