Third-party sharing stops when consumer opts out
Why it matters
Recording an opt-out preference without actually stopping data sharing is a CCPA § 1798.120 violation more egregious than having no opt-out at all — it deceives the consumer into believing their request was honored. The most common pattern: opt-out cookie is set correctly, suppressing one pixel (e.g., Facebook), while server-side Segment track() calls or a Google Analytics identify() still fire unconditionally because they were wired into API route handlers that never check the opt-out flag. Each page load where a third-party sharing call fires for an opted-out consumer is a separate violation. This check requires tracing the enforcement gap, not just the preference storage.
Severity rationale
Medium because the gap between stored opt-out preference and actual enforcement of that preference across all sharing touchpoints is a concrete CCPA § 1798.120 violation per sharing event, even when the opt-out UI exists.
Remediation
Create a centralized isUserOptedOut() helper that both client-side pixels and server-side analytics calls must pass through. Enumerate every third-party sharing touchpoint and confirm each one is gated.
// lib/analytics.ts — single source of truth for opt-out check
import { cookies } from 'next/headers'
export async function isUserOptedOut(userId?: string): Promise<boolean> {
if (userId) {
const pref = await db.privacyPreference.findFirst({ where: { userId, type: 'sale_sharing' } })
if (pref) return true
}
const cookieStore = cookies()
return cookieStore.get('ccpa_opt_out')?.value === '1'
}
// Server-side event — every analytics call uses this wrapper
export async function trackServerEvent(event: string, props: Record<string, unknown>, userId?: string) {
if (await isUserOptedOut(userId)) return
await segment.track({ event, properties: props, userId })
}
Search src/ for segment.track, gtag, fbq, analytics.identify, and mixpanel.track calls and confirm each one is wrapped or gated. Document the gating coverage in PRIVACY_OPERATIONS.md.
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 CCPA/CPRA Readiness Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- ccpa · §1798.120 — Opt-out of sale or sharing — sharing must actually stop, not merely be recorded
- ccpa · §1798.140(ah) — "Sharing" definition — cross-context behavioral advertising constitutes sharing
- cwe · CWE-359 — Exposure of private personal information — opt-out bypass allows continued unauthorized disclosure
- owasp:2021 · A01 — Broken Access Control — failure to enforce data-sharing restriction
Taxons
History
- 2026-04-18·v1.0.0·Initial import from ccpa-readiness·automated