Personally identifiable information (PII) sent to Firebase Analytics

ID

dart.privacy.analytics_pii

Severity

high

Remediation Complexity

trivial

Remediation Risk

medium

Remediation Effort

low

Resource

Privacy

Language

Dart

Description

Personally identifiable information (email, phone, SSN, password, full name, home address, date of birth, credit card) is sent to Firebase Analytics via setUserProperty, setUserId, or logEvent. Google’s Analytics terms forbid uploading PII and applicable privacy laws (GDPR, CCPA, LGPD) restrict this kind of identifier sharing without explicit consent.

Rationale

Firebase Analytics is designed for product-usage telemetry — bucketed properties like plan_tier, theme, country_code. It is explicitly not designed for PII storage, and Google’s [Terms of Service](https://firebase.google.com/terms/analytics) prohibit uploading PII. Apps that ignore this:

  • Risk account suspension of their Firebase project.

  • Risk regulatory fines under GDPR Art. 6 / Art. 9, CCPA, or LGPD — the data is processed without a lawful basis and transferred to Google as a processor without the required contractual safeguards.

  • Build a permanent off-device record of who-did-what, accessible from any dashboard login and from Google’s BigQuery export. A breach of the Analytics dashboard becomes a breach of every user’s personal data.

The rule catches:

  • setUserProperty(name: 'email', value: …​) and similar PII keys (phone_number, ssn, dob, date_of_birth, home_address, credit_card, password, full_name, passport, drivers_license).

  • setUserId('alice@example.com') and setUserId('+1 555…') — pseudonymous user IDs must NOT be the real email or phone.

  • logEvent(name: …​, parameters: {'email': …}) — PII keys in the event parameters map.

The following code illustrates a vulnerable pattern detected by this rule:

class TrackPii {
  Future<void> userProperties(FirebaseAnalytics analytics, String email, String phone) async {
    // VULNERABLE: Personally identifiable information (PII) sent to Firebase Analytics
    await analytics.setUserProperty(name: 'email', value: email);
    // VULNERABLE: Personally identifiable information (PII) sent to Firebase Analytics
    await analytics.setUserProperty(name: 'phone_number', value: phone);
    // VULNERABLE: Personally identifiable information (PII) sent to Firebase Analytics
    await analytics.setUserProperty(name: 'ssn', value: '111-22-3333');
    // VULNERABLE: Personally identifiable information (PII) sent to Firebase Analytics
    await analytics.setUserProperty(name: 'date_of_birth', value: '1990-01-01');
    // VULNERABLE: Personally identifiable information (PII) sent to Firebase Analytics
    await analytics.setUserProperty(name: 'home_address', value: '742 Evergreen Terrace');
    // VULNERABLE: Personally identifiable information (PII) sent to Firebase Analytics
    await analytics.setUserProperty(name: 'credit_card', value: '4111111111111111');
  }

  Future<void> userIdAsPii(FirebaseAnalytics analytics) async {
    await analytics.setUserId(id: 'alice@example.com');
    await analytics.setUserId(id: '+1 (555) 867-5309');
  }
}

Remediation

Use a stable, pseudonymous user ID (usr_<random>, the Firebase Auth UID, or a hash of the email) and store bucketed user properties only. Forward the real PII to a controlled backend with an explicit consent flow, not to Analytics.

// Vulnerable
await analytics.setUserProperty(name: 'email', value: user.email);
await analytics.setUserId(id: user.email);
await analytics.logEvent(name: 'signup', parameters: {'email': user.email});

// Fixed
await analytics.setUserId(id: 'usr_${user.uid}');                // pseudonymous
await analytics.setUserProperty(name: 'plan_tier', value: 'pro');// bucketed
await analytics.logEvent(name: 'signup', parameters: {
  'plan_tier': 'pro',
  'signup_method': 'oauth_google',                                // categorical
});

Configuration

This detector does not need any configuration.

References

© 2026 Xygeni. All rights reserved