Skip to content

Firebase Authentication: Anonymous Authentication Unnecessarily Enabled

Name: Anonymous Authentication Unnecessarily Enabled

Applicable Services: Firebase Authentication

Description

Technical Configuration Issue

The Configuration Flaw: Anonymous Authentication is enabled in Firebase Authentication but may not be explicitly required for the application's functionality. This creates an unnecessary attack surface and potential entry point for malicious actors.

Intended Behavior: Anonymous Authentication should only be enabled when the application specifically requires temporary, anonymous user sessions for features like guest checkout, trial access, or progressive onboarding.

The Risk: Unnecessary anonymous authentication expands the attack surface, can lead to resource abuse, quota exhaustion, and potential data exposure if security rules are not properly configured for anonymous users.

Impact

Potential Consequences

Unnecessary anonymous authentication can lead to several security and operational issues:

  • Expanded Attack Surface: Provides an additional entry point for attackers to probe application vulnerabilities
  • Resource Abuse: Anonymous users can consume resources without accountability or rate limiting
  • Data Exposure: Overly permissive security rules may grant anonymous users unintended access to sensitive data
  • Quota Exhaustion: Unlimited anonymous user creation can exhaust Firebase quotas and increase costs
  • Account Clutter: Accumulation of unused anonymous accounts affects database performance and billing
  • Security Rule Complexity: Additional authentication state increases complexity of security rule management

Example Attack Scenarios

Exploit Scenario: Anonymous User Resource Abuse

The Vulnerable Configuration: Anonymous Authentication is enabled with permissive security rules:

// Firestore Security Rules - Overly Permissive
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /public_data/{document} {
      // Allows any authenticated user, including anonymous
      allow read, write: if request.auth != null;
    }
  }
}

Attack Steps: 1. Attacker discovers anonymous authentication is enabled 2. Creates multiple anonymous accounts to bypass rate limiting 3. Uses anonymous accounts to spam public collections with malicious data 4. Exploits lack of accountability to perform reconnaissance 5. Potentially escalates to more serious attacks using gathered information

Exploit Scenario: Anonymous User Data Harvesting

The Attack: 1. Attacker creates anonymous account to gain basic authentication 2. Exploits overly permissive security rules that allow "any authenticated user" 3. Systematically harvests publicly accessible data using anonymous credentials 4. Uses anonymous status to avoid detection and accountability 5. Gathers intelligence for more targeted attacks against legitimate users

Detection

Check Anonymous Authentication Status

Firebase Console

  1. Go to Firebase Console → Authentication → Sign-in method
  2. Look for "Anonymous" in the sign-in providers list
  3. Check if it's enabled (toggle switch is on)

Using Firebase Admin SDK

const admin = require('firebase-admin');

async function checkAnonymousAuthStatus() {
  try {
    // Get project configuration
    const projectConfig = await admin.auth().projectConfigManager().getProjectConfig();

    // Check if anonymous authentication is enabled
    const anonymousEnabled = projectConfig.signInConfig?.anonymousEnabled;
    console.log('Anonymous Authentication Enabled:', anonymousEnabled);

    // Count anonymous users
    const listUsers = await admin.auth().listUsers();
    const anonymousUsers = listUsers.users.filter(user => 
      user.providerData.length === 0 // Anonymous users have no providers
    );

    console.log('Anonymous Users Count:', anonymousUsers.length);

    return {
      enabled: anonymousEnabled,
      anonymousUserCount: anonymousUsers.length
    };

  } catch (error) {
    console.error('Error checking anonymous auth status:', error);
  }
}

Using gcloud CLI

# Get authentication configuration
gcloud identity toolkit config describe

# Look for anonymous authentication settings
gcloud identity toolkit config describe --format="value(signIn.anonymousEnabled)"

Audit Anonymous User Usage

// Analyze anonymous user patterns
async function auditAnonymousUsers() {
  const listUsers = await admin.auth().listUsers();
  const anonymousUsers = listUsers.users.filter(user => 
    user.providerData.length === 0
  );

  const analysis = {
    total: anonymousUsers.length,
    recentlyActive: 0,
    neverConverted: 0,
    oldAccounts: 0
  };

  const thirtyDaysAgo = new Date();
  thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);

  anonymousUsers.forEach(user => {
    const lastSignIn = new Date(user.metadata.lastSignInTime);
    const createdAt = new Date(user.metadata.creationTime);

    if (lastSignIn > thirtyDaysAgo) {
      analysis.recentlyActive++;
    }

    if (!user.metadata.lastSignInTime) {
      analysis.neverConverted++;
    }

    if (createdAt < thirtyDaysAgo) {
      analysis.oldAccounts++;
    }
  });

  return analysis;
}

Remediation

Step 1: Assess Application Requirements

Before disabling anonymous authentication, evaluate if your application truly needs it:

Legitimate Use Cases for Anonymous Authentication

  • Guest Checkout: E-commerce applications allowing purchases without registration
  • Trial Access: Apps providing limited functionality before requiring registration
  • Progressive Onboarding: Gradually converting anonymous users to registered users
  • Offline-First Apps: Apps that work offline and sync when users register
  • Content Preview: Allowing content browsing before requiring sign-up

Questions to Ask

  1. Do you have specific features that require anonymous access?
  2. Are anonymous users being converted to registered users?
  3. Are there alternative approaches (like requiring registration upfront)?
  4. Do anonymous users access sensitive data or perform critical operations?

Step 2: Disable Anonymous Authentication (If Not Needed)

Firebase Console

  1. Go to Firebase Console → Authentication → Sign-in method
  2. Find "Anonymous" in the providers list
  3. Click on "Anonymous" to open settings
  4. Toggle off "Enable" switch
  5. Save changes

Using gcloud CLI

# Disable anonymous authentication
gcloud identity toolkit config update --disable-anonymous-sign-in

Using Admin SDK

async function disableAnonymousAuth() {
  try {
    await admin.auth().projectConfigManager().updateProjectConfig({
      signInConfig: {
        anonymousEnabled: false
      }
    });

    console.log('Anonymous authentication disabled');
  } catch (error) {
    console.error('Error disabling anonymous auth:', error);
  }
}

Step 3: Handle Existing Anonymous Users

Option 1: Convert Anonymous Users to Registered Users

// Client-side anonymous user conversion
import { linkWithCredential, EmailAuthProvider } from 'firebase/auth';

async function convertAnonymousUser(email, password) {
  const user = auth.currentUser;

  if (user && user.isAnonymous) {
    try {
      const credential = EmailAuthProvider.credential(email, password);
      const result = await linkWithCredential(user, credential);
      console.log('Anonymous user converted:', result.user.uid);
    } catch (error) {
      console.error('Conversion failed:', error);
    }
  }
}

Option 2: Clean Up Unused Anonymous Accounts

// Server-side cleanup of old anonymous accounts
async function cleanupAnonymousUsers() {
  const listUsers = await admin.auth().listUsers();
  const anonymousUsers = listUsers.users.filter(user => 
    user.providerData.length === 0
  );

  const thirtyDaysAgo = new Date();
  thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);

  const usersToDelete = anonymousUsers.filter(user => {
    const lastSignIn = new Date(user.metadata.lastSignInTime || user.metadata.creationTime);
    return lastSignIn < thirtyDaysAgo;
  });

  // Delete in batches to avoid rate limits
  const batchSize = 100;
  for (let i = 0; i < usersToDelete.length; i += batchSize) {
    const batch = usersToDelete.slice(i, i + batchSize);
    const uids = batch.map(user => user.uid);

    try {
      await admin.auth().deleteUsers(uids);
      console.log(`Deleted ${uids.length} anonymous users`);
    } catch (error) {
      console.error('Error deleting users:', error);
    }
  }
}

Step 4: Update Security Rules

If keeping anonymous authentication, ensure security rules properly handle anonymous users:

Firestore Security Rules

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Restrict anonymous users to read-only access to specific collections
    match /public_content/{document} {
      allow read: if request.auth != null; // Includes anonymous users
      allow write: if request.auth != null && !isAnonymous();
    }

    // Completely restrict anonymous users from sensitive data
    match /user_data/{userId} {
      allow read, write: if request.auth != null 
                        && !isAnonymous() 
                        && request.auth.uid == userId;
    }

    // Helper function to check if user is anonymous
    function isAnonymous() {
      return request.auth.token.firebase.sign_in_provider == 'anonymous';
    }
  }
}

Storage Security Rules

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    // Allow anonymous users to read public files only
    match /public/{allPaths=**} {
      allow read: if request.auth != null;
      allow write: if request.auth != null && !isAnonymous();
    }

    // Restrict user files to non-anonymous users only
    match /users/{userId}/{allPaths=**} {
      allow read, write: if request.auth != null 
                        && !isAnonymous() 
                        && request.auth.uid == userId;
    }

    function isAnonymous() {
      return request.auth.token.firebase.sign_in_provider == 'anonymous';
    }
  }
}

Step 5: Implement Anonymous User Monitoring

// Monitor anonymous user activity
exports.monitorAnonymousUsers = functions.auth.user().onCreate(async (user) => {
  if (user.providerData.length === 0) { // Anonymous user
    // Log anonymous user creation
    console.log('Anonymous user created:', user.uid);

    // Set up conversion tracking
    await admin.firestore().collection('user_analytics').doc(user.uid).set({
      isAnonymous: true,
      createdAt: admin.firestore.FieldValue.serverTimestamp(),
      lastActivity: admin.firestore.FieldValue.serverTimestamp(),
      converted: false
    });

    // Schedule cleanup if not converted within 30 days
    const scheduledTime = new Date();
    scheduledTime.setDate(scheduledTime.getDate() + 30);

    await admin.firestore().collection('scheduled_tasks').add({
      type: 'cleanup_anonymous_user',
      userId: user.uid,
      scheduledFor: scheduledTime
    });
  }
});

// Monitor anonymous user conversion
exports.trackAnonymousConversion = functions.auth.user().onWrite(async (change) => {
  const before = change.before?.data();
  const after = change.after?.data();

  // Check if user converted from anonymous to registered
  if (before?.providerData?.length === 0 && after?.providerData?.length > 0) {
    await admin.firestore().collection('user_analytics').doc(after.uid).update({
      converted: true,
      convertedAt: admin.firestore.FieldValue.serverTimestamp()
    });

    console.log('Anonymous user converted:', after.uid);
  }
});

Prevention

  • Principle of Least Privilege: Only enable authentication methods that are specifically required
  • Regular Audits: Periodically review enabled authentication providers
  • User Lifecycle Management: Implement automatic cleanup of unused anonymous accounts
  • Security Rule Reviews: Ensure security rules properly handle anonymous users
  • Monitoring: Track anonymous user creation and conversion rates
  • Documentation: Clearly document why each authentication method is enabled

Best Practices

If Anonymous Authentication is Required

  • Limited Scope: Restrict anonymous users to read-only access where possible
  • Conversion Incentives: Provide clear benefits for converting to registered accounts
  • Automatic Cleanup: Implement lifecycle policies to remove unused anonymous accounts
  • Rate Limiting: Apply stricter rate limits to anonymous users
  • Monitoring: Track anonymous user behavior and conversion rates

Security Rule Patterns

// Helper functions for security rules
function isAnonymous() {
  return request.auth.token.firebase.sign_in_provider == 'anonymous';
}

function isVerifiedUser() {
  return request.auth != null 
         && !isAnonymous() 
         && request.auth.token.email_verified == true;
}

function isOwnerOrVerified(userId) {
  return isVerifiedUser() && request.auth.uid == userId;
}

References