Analytics configured with IP masking; no user IDs sent without explicit consent
Why it matters
GDPR Art. 25 (data protection by design) requires that analytics configurations minimize data collection by default — and the default GA4 configuration does not do this. Without Consent Mode v2 and analytics_storage: 'denied' as the default state, GA4 collects full IP addresses and sets cookies before any user consent is obtained. ePrivacy Art. 5(3) makes this unlawful for EU users without prior consent. ISO-27001:2022 A.5.34 requires that privacy controls be applied at the point of processing, not as an afterthought. Passing raw user email to analytics.identify() also creates a direct PII leak to a third-party processor — this is an Art. 28 issue on top of the consent failure.
Severity rationale
Info because misconfigured analytics is a procedural privacy failure rather than a direct security vulnerability, but regulators treat it as a consent mechanism failure and issue fines accordingly.
Remediation
Initialize GA4 with Consent Mode v2 so analytics is denied by default and only activates after the user accepts in the consent banner.
// In your <head>, before the GA4 script tag loads:
window.dataLayer = window.dataLayer || []
function gtag(...args: unknown[]) { window.dataLayer.push(args) }
// Deny all by default
gtag('consent', 'default', {
analytics_storage: 'denied',
ad_storage: 'denied',
ad_user_data: 'denied',
ad_personalization: 'denied',
})
// Call after user accepts analytics in the consent banner:
gtag('consent', 'update', { analytics_storage: 'granted' })
For identity calls, pass a pseudonymous ID (see pii-separation pattern) never the raw email. If migrating is complex, consider switching to Plausible or Fathom — both are GDPR-compliant by design with no cookies, no IP storage, and no consent banner requirement for basic analytics.
Detection
-
ID:
analytics-privacy-configured -
Severity:
info -
What to look for: Enumerate every relevant item. Check the analytics service configuration in the codebase. For Google Analytics 4 (GA4): look for the
gtaginitialization in the HTML layout — verify that Consent Mode v2 is configured (gtag('consent', 'default', ...)) and thatanalytics_storage: 'denied'is the default until consent is granted. For GA Universal/GA3: check foranonymize_ip: truein the config. For Segment: verify that PII fields (email, name, phone) are not passed toanalytics.identify(). For Mixpanel or Amplitude: checkidentify()calls. For Plausible or Fathom: these are privacy-friendly by design (no IP storage, no cookies) — confirm the correct tracking script is in use and check their configuration for custom domains. -
Pass criteria: At least 1 of the following conditions is met. Analytics service has IP masking or anonymization enabled (or uses a privacy-first tool like Plausible/Fathom that doesn't store IPs). User IDs sent to analytics are pseudonymous (UUID or hash), not email or name. Analytics scripts are only loaded/activated after the user grants analytics consent.
-
Fail criteria: IP masking disabled in GA configuration. User email or name passed directly to analytics identify calls. Analytics loads before or without consent.
-
Skip (N/A) when: Application does not use analytics.
-
Detail on fail: Example:
"GA4 configured without Consent Mode v2. analytics_storage not set to 'denied' by default. Full IP addresses logged."or"Segment identify() called with user.email as the userId without consent check.". -
Remediation: Configure analytics for privacy compliance:
// GA4 Consent Mode v2 — initialize before gtag loads // In your <head>, before the GA4 script tag: window.dataLayer = window.dataLayer || [] function gtag(...args: unknown[]) { window.dataLayer.push(args) } // Default: deny all until user consents gtag('consent', 'default', { analytics_storage: 'denied', ad_storage: 'denied', ad_user_data: 'denied', ad_personalization: 'denied', }) // After user accepts analytics in consent banner: gtag('consent', 'update', { analytics_storage: 'granted' })For pseudonymous user IDs in all analytics tools, see the remediation for
pii-separationcheck above. If budget allows, migrate to Plausible or Fathom — both are GDPR-compliant by design, require no consent banner for analytics, and provide simpler compliance posture.
External references
- gdpr · Art. 25 — Data protection by design and by default
- gdpr · Art. 32 — Security of processing — appropriate technical measures
- eprivacy · Art. 5(3) — Consent required before storing or accessing information on terminal equipment
- iso-27001:2022 · A.5.34 — Privacy and protection of PII
Taxons
History
- 2026-04-18·v1.0.0·Initial import from data-protection·automated