All consent changes logged with actor, timestamp, and reason
Why it matters
GDPR Article 7(1) requires you to demonstrate that consent was given — but demonstrating how and by whom a consent state was established requires an operational audit trail beyond the consent record itself. GDPR Article 30 requires records of processing activities. CWE-778 (Insufficient Logging) covers the broader risk: without logging the actor and source for every consent change, you cannot answer "who bulk-imported this contact without consent?" or "which admin override changed this contact's scope?" A consent record showing granted = true with no audit trail is legally weaker than one with a clear chain of custody. NIST AU-2 mandates logging of all events that could be relevant to regulatory compliance.
Severity rationale
High because consent change logging gaps make it impossible to reconstruct the chain of custody for any consent state, undermining GDPR Art. 7(1)'s demonstrability requirement and exposing admin override and bulk import paths to undetectable misuse.
Remediation
Add a centralized logConsentChange() function and call it from every consent mutation path — web form, admin panel, bulk import, and API:
// src/lib/compliance/audit.ts
export async function logConsentChange(event: {
contactId: string
scope: string
previousState: boolean | null
newState: boolean
actor: string // user ID, API key ID, or 'system'
actorType: 'user' | 'api-key' | 'system'
source: string // 'signup-form', 'admin-panel', 'bulk-import', 'unsubscribe-link'
reason?: string
}) {
await db.auditLog.create({
data: {
entityType: 'consent',
entityId: `${event.contactId}:${event.scope}`,
action: event.newState ? 'consent_granted' : 'consent_revoked',
actor: event.actor,
actorType: event.actorType,
source: event.source,
metadata: { previousState: event.previousState, newState: event.newState },
createdAt: new Date()
}
})
}
Grep src/ for all consent record creation and update paths and confirm each calls logConsentChange(). Bulk imports log one entry per batch with the row count in metadata.
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 Compliance & Consent Engine Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- gdpr · Art. 7(1) — Controller must demonstrate consent was given — operational audit trail required
- gdpr · Art. 30 — Records of processing activities
- cwe · CWE-778 — Insufficient logging — consent changes not logged with actor/source
- iso-27001:2022 · A.8.15 — Logging — who changed what and when
- nist:rev5 · AU-2 — Event logging — required event types
Taxons
History
- 2026-04-18·v1.0.0·Initial import from compliance-consent-engine·automated