Archive restoration verified annually
Why it matters
SOX §802 requires that covered companies preserve audit records for 7 years, and regulators during examinations will ask not just whether archives exist but whether they can actually be restored to a readable state. Backup processes that have never been tested are not controls — they are theoretical controls. NIST 800-53 AU-11 requires that organizations retain audit logs for a defined period and that archived records remain accessible. NIST SP 800-34 (Contingency Planning Guide) requires that recovery procedures be tested. A compressed, encrypted archive on Glacier that has never been decompressed, decrypted, and verified is an unknown quantity — and discovering at examination time that the archive is corrupted or the decryption key is lost is a SOX material weakness.
Severity rationale
Info because untested restoration is a latent risk rather than an immediate vulnerability — the failure mode only becomes critical when an actual restoration is required during an incident or examination.
Remediation
Schedule an annual restoration test via cron in src/jobs/archive-test.ts and log each run to archive_restoration_tests:
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
import zlib from 'zlib';
async function testArchiveRestoration(targetYear: number) {
const s3 = new S3Client({ region: process.env.AWS_REGION });
const obj = await s3.send(new GetObjectCommand({
Bucket: process.env.AUDIT_ARCHIVE_BUCKET!,
Key: `transactions_${targetYear}.json.gz`
}));
const body = await obj.Body!.transformToByteArray();
const decompressed = zlib.gunzipSync(body);
const records: AuditRecord[] = JSON.parse(decompressed.toString());
// Sample-verify 100 random records
const sample = records.sort(() => Math.random() - 0.5).slice(0, 100);
const allValid = sample.every(r => verifyLogSignature(r, process.env.AUDIT_SIGNING_KEY!));
await db('archive_restoration_tests').insert({
test_date: new Date(), archive_year: targetYear,
records_verified: records.length, status: allValid ? 'success' : 'failed'
});
if (!allValid) await alertOps('Archive integrity check failed', { targetYear });
}
// Run once per year (first Monday of January)
cron.schedule('0 8 1-7 1 1', () => testArchiveRestoration(new Date().getFullYear() - 2));
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the Financial Audit Trail Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- nist:rev5 · AU-11 — Audit Record Retention — verify recoverability of retained records
- sox · Section 802 — Criminal penalties for altering documents — requires demonstrable ability to retrieve records
- nist:rev1 · SP-800-34 — Contingency Planning Guide for Federal Information Systems
Taxons
History
- 2026-04-18·v1.0.0·Initial import from finserv-audit-trail·automated