No tracking identifiers read before ATT consent is received
Why it matters
Displaying an ATT prompt but reading the tracking identifier before the user responds — or transmitting a device-persistent ID to a third party before ATT resolves — defeats the purpose of the consent mechanism entirely. Under GDPR Art.7, consent must precede processing; under CCPA §1798.120, users have the right to opt out before sharing occurs. OWASP 2021 A04 (Insecure Design) applies when consent architecture is structurally bypassed. Apple's App Review detects this pattern with instrumentation: they see SDK network calls before the ATT dialog appears in their testing, and apps fail review for it.
Severity rationale
High because transmitting tracking identifiers before ATT consent is obtained constitutes pre-consent data collection that violates Apple policy, GDPR Art.7, and CCPA §1798.120.
Remediation
Gate every identifier read and third-party transmission on ATT status resolution:
import { getTrackingStatus } from 'expo-tracking-transparency';
const status = await getTrackingStatus();
if (status === 'authorized') {
const advertisingId = await getAdvertisingId();
analytics.identify(advertisingId);
} else {
// Use ephemeral session ID only
}
Audit every track() and identify() call in src/analytics/ or equivalent for whether it includes a device-persistent or user-persistent identifier. Replace persistent device IDs with ephemeral session IDs (generated fresh each app launch) for pre-consent analytics. Any DeviceInfo.getUniqueId() value passed to a third-party service must be gated the same way.
Detection
- ID:
no-tracking-before-consent - Severity:
high - What to look for: Count all relevant instances and enumerate each. This check goes deeper than the ATT framework check — look for any code path that reads tracking-adjacent identifiers before consent:
UIDevice.current.identifierForVendor(IDFV — not IDFA, but if shared across apps it may require ATT); any hashed email or phone number sent to an ad network before login; fingerprinting signals (screen resolution, OS version, installed font list, battery level, CPU count) collected and sent to a third-party server;DeviceInfo.getUniqueId()(fromreact-native-device-info) sent to an analytics service before ATT consent. For React Native, search forNativeModules.RNDeviceInfo,DeviceInfo.getUniqueId,DeviceInfo.getAdvertisingId,getAdvertisingId(),TrackingTransparency.getAdvertisingId()calls without a preceding ATT status check. For Flutter, look forAdvertisingId.idordevice_info_plusunique ID usage passed to analytics before consent. Also check whether any analytics event sent on app launch includes a persistent user or device identifier. - Pass criteria: No tracking identifier is read or transmitted to a third party before ATT consent is obtained. At least 1 implementation must be verified. IDFV is only used for first-party analytics (not shared cross-app or with ad networks before consent).
- Fail criteria: Any tracking identifier read or transmitted to a third party before the ATT prompt completes and receives user authorization.
- Skip (N/A) when: No advertising or cross-app tracking SDKs detected; app does not read IDFA or share device identifiers with third parties.
- Detail on fail:
"getAdvertisingId() called in src/analytics/startup.ts before ATT prompt — IDFA transmitted to analytics service on app launch regardless of consent"or"DeviceInfo.getUniqueId() passed to third-party analytics API in app initialization before any consent flow" - Remediation: Even if you display an ATT prompt, reading the identifier before the user responds and transmitting it defeats the purpose of ATT and violates Apple's policy.
- Gate ALL identifier reads and third-party transmissions on ATT status:
import { getTrackingStatus } from 'expo-tracking-transparency'; const status = await getTrackingStatus(); if (status === 'authorized') { const advertisingId = await getAdvertisingId(); analytics.identify(advertisingId); } else { // Use anonymous session ID only } - Audit every analytics
track()andidentify()call site for whether it includes a persistent device or user identifier - Use ephemeral session IDs (generated fresh each app launch) for anonymous analytics instead of device-persistent IDs
- Gate ALL identifier reads and third-party transmissions on ATT status:
External references
- cwe · CWE-359 — Exposure of Private Personal Information to an Unauthorized Actor
- gdpr · Art.7 — Conditions for consent
- ccpa · §1798.120 — Right to opt-out of sale of personal information
- owasp:2021 · A04 — Insecure Design
Taxons
History
- 2026-04-18·v1.0.0·Initial import from app-store-privacy-data·automated