GDPR Articles 13 and 14 require that consent be informed — the contact must know what they are agreeing to at the time they agree. If your privacy policy changes substantially and you cannot show that pre-existing consents were obtained under the old policy (not the new one), you cannot determine whether those consents remain valid for processing under the updated terms. CCPA §1798.100 similarly requires you to be able to characterize what data was collected and under what notice. A policy_version field is the mechanism that makes this determination possible; without it, every privacy policy update potentially invalidates your entire consent corpus.
Medium because the gap only becomes an enforcement problem after a material privacy policy change, but by then the historical consents are already unverifiable and re-collection from your entire list may be required.
Define a version constant and populate it on every consent creation path. Place the constant in a shared config file so a single change updates all collection points:
// src/lib/consent/constants.ts
export const CURRENT_POLICY_VERSION = '2025-01-15'
// Bump this string whenever the privacy policy changes materially
// src/lib/consent/create.ts
import { CURRENT_POLICY_VERSION } from './constants'
await db.consentRecord.create({
data: {
contactId,
scope: 'marketing',
granted: true,
source: 'signup-form',
policyVersion: CURRENT_POLICY_VERSION
}
})
Search all consent-creation paths in src/ for any that do not import and use CURRENT_POLICY_VERSION, and add the field. Run a query against production to count rows where policy_version IS NULL — these represent consents of unknown vintage.
ID: compliance-consent-engine.consent-storage.version-tracking
Severity: medium
What to look for: Check whether the consent record stores which version of the privacy policy or terms of service was in effect when the user gave consent. This is required to demonstrate that the consent was informed — a consent given under a 2022 privacy policy may not be valid for a substantially changed 2025 policy. Look for a policy_version, tos_version, or consent_version column.
Pass criteria: Consent records include the version of the privacy policy that was displayed at the time of consent capture. The version is a meaningful identifier (e.g., a date string, a semver, or a document hash) — not always null or a hardcoded constant. Quote the actual policy version constant or configuration value found in the codebase. Count all consent-creation code paths and verify at least 100% populate the version field.
Fail criteria: No policy version field on consent records. Or the field exists but is always null or a hardcoded placeholder.
Skip (N/A) when: No consent collection in the application.
Detail on fail: "consent_records table has no policy_version column" or "policy_version column exists but is NULL on 12,400 of 12,400 records — never populated"
Remediation: Add the field and populate it at capture time:
// Define version as a constant, bump it when policy changes materially
const CURRENT_POLICY_VERSION = '2025-01-15'
await db.consentRecord.create({
data: {
contactId,
scope: 'marketing',
granted: true,
source: 'signup-form',
policyVersion: CURRENT_POLICY_VERSION
}
})