Exposed Secrets in Firebase Projects
Firebase API keys (the ones in firebaseConfig) are designed to be public and are not secrets. The real danger comes from exposing Firebase Admin SDK credentials, service account JSON files, and legacy database secrets that bypass all security rules.
Scan Your Firebase AppHow It Happens
The Firebase client config (apiKey, authDomain, projectId, etc.) is embedded in every frontend application. This is safe and intended. Scanners that flag these as "exposed API keys" are producing false positives because Firebase security is enforced by Security Rules and Authentication, not by hiding the config. The actual secrets that must never be exposed are Firebase Admin SDK credentials. The Admin SDK private key (a JSON file containing a private_key field) grants full administrative access to the Firebase project, bypassing all Security Rules, Authentication checks, and rate limits. Developers expose Admin SDK credentials by committing service account JSON files to Git repositories, embedding them in frontend code to perform admin operations, or deploying them in environment variables with NEXT_PUBLIC_ or VITE_ prefixes. Another common pattern is using the legacy Firebase Realtime Database secret (a long alphanumeric string) in client code, which bypasses Realtime Database rules entirely.
Impact
An exposed Firebase Admin SDK key gives the attacker god-mode access to the entire Firebase project. They can read and write all Firestore and Realtime Database data, delete collections, manage users (create, delete, modify any account), send push notifications, access Cloud Storage, and invoke Cloud Functions with admin context. Unlike the public Firebase config which is scoped by Security Rules, the Admin SDK bypasses all rules. There is no defense once this key is leaked other than rotating it. Exposed service account JSON files also provide access to Google Cloud resources beyond Firebase, depending on the service account's IAM roles. An attacker could gain access to Cloud Storage buckets, BigQuery datasets, or other GCP services tied to the same project.
How to Detect
Search your codebase and JavaScript bundles for "private_key" (the field in service account JSON), "type": "service_account" (the service account identifier), and any strings matching the service account key format (-----BEGIN PRIVATE KEY-----). Check Git history for committed JSON files with names like serviceAccountKey.json, firebase-admin-key.json, or similar patterns. Scan with tools like truffleHog or gitleaks. Vibe App Scanner distinguishes between safe public Firebase config and dangerous exposed Admin SDK credentials. It flags only the real secrets while correctly identifying Firebase API keys as safe.
How to Fix
Remove any Admin SDK credentials from frontend code and Git repositories immediately. Rotate the service account key in the Google Cloud Console (IAM > Service Accounts > Keys) and delete the compromised key. Store Admin SDK credentials only in server-side environments: Cloud Functions, your own backend server, or CI/CD secrets. Never reference them from client-side code or include them in environment variables with public prefixes. For operations that require admin access from the frontend, create a Cloud Function or server endpoint that performs the admin operation and expose it through a callable function or API endpoint that validates the user's permissions. Regularly audit your Git repository for committed secrets and set up pre-commit hooks that block service account JSON files from being committed.
Code Examples
Firebase initialization patterns
// DANGEROUS: Admin SDK in frontend code
import admin from 'firebase-admin'
import serviceAccount from './serviceAccountKey.json'
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
})
// This key bypasses ALL security rules// Frontend: public config only (this is SAFE)
import { initializeApp } from 'firebase/app'
const firebaseConfig = {
apiKey: "AIzaSy...", // Public by design
authDomain: "app.firebaseapp.com",
projectId: "my-app",
}
const app = initializeApp(firebaseConfig)
// Server/Cloud Function: Admin SDK is OK here
import admin from 'firebase-admin'
admin.initializeApp() // Uses default credentials in GCPFrequently Asked Questions
Is my Firebase API key (AIzaSy...) a secret?
No. The Firebase API key in your firebaseConfig is designed to be public. It identifies your project but does not grant access to data. Security is enforced by Firestore Security Rules and Firebase Authentication, not by hiding this key.
What Firebase credentials ARE secrets?
The Admin SDK private key (service account JSON with a private_key field), the legacy Realtime Database secret, and any Cloud Function environment variables containing API keys for third-party services. These must never appear in frontend code or public repositories.
How do I rotate a compromised Admin SDK key?
Go to Google Cloud Console > IAM & Admin > Service Accounts. Select the compromised service account, go to Keys, delete the compromised key, and create a new one. Update your server-side code with the new key.
Should I restrict my Firebase API key?
You can add API key restrictions in the Google Cloud Console to limit which APIs and websites can use the key. This is a defense-in-depth measure but is not a substitute for Security Rules.
Related Security Resources
Is Your App Vulnerable?
VAS automatically scans for exposed api keys and other security issues in Firebase apps. Get actionable results with step-by-step fixes.
Scans from $5, results in minutes.