HIGH webhook abusefirestore

Webhook Abuse in Firestore

How Webhook Abuse Manifests in Firestore

Firestore itself does not have native webhooks; instead, it uses Cloud Functions triggers (e.g., functions.firestore.document(...).onWrite(...)) to react to database events. However, developers often expose these functions via HTTP triggers or create separate HTTP endpoints that mimic Firestore event structures, effectively turning them into webhooks. Attackers exploit these endpoints when they are improperly secured, leading to data theft, unauthorized operations, or resource exhaustion.

Common Firestore-specific attack patterns include:

  • Unauthenticated Event Injection: An attacker directly calls an HTTP-triggered Cloud Function that expects a Firestore event payload. If the function does not validate the request origin (e.g., via Firebase Auth token or App Check), the attacker can forge a data field to perform arbitrary writes or reads, bypassing Firestore security rules because the function runs with admin privileges.
  • Event Payload Tampering: Firestore triggers pass an event object containing before and after snapshots. A vulnerable function might use these snapshots without verifying they came from Firestore. An attacker could inject a payload with { "before": null, "after": { "fields": { "secret": { "stringValue": "leaked" } } } } to trick the function into processing unauthorized data.
  • Data Exfiltration via Response: Some functions return Firestore data in their HTTP response. If the endpoint lacks authentication, an attacker can query it to retrieve sensitive documents, effectively turning the function into a data proxy that circumvents Firestore rules.
  • Replay Attacks: Firestore events include timestamps and document paths. An attacker who captures a legitimate event could replay it to trigger duplicate actions (e.g., creating orders), especially if the function does not check for idempotency or event freshness.

For example, consider a Cloud Function meant to sync Firestore changes to an external system:

exports.syncToExternal = functions.https.onRequest(async (req, res) => {
  const doc = req.body.after;
  // VULNERABLE: No verification that req came from Firestore
  await externalApi.post('/data', doc);
  res.status(200).send('OK');
});

If this endpoint is publicly accessible, an attacker can send a crafted POST request with any Firestore document structure, causing the function to write arbitrary data to the external system.

Firestore-Specific Detection

To identify webhook abuse risks in Firestore-related endpoints, look for:

  • Missing Authentication on HTTP Triggers: Check if Cloud Functions with functions.https.onRequest enforce Firebase ID token verification or App Check. A function that only checks req.method === 'POST' is vulnerable.
  • Overly Permissive Security Rules: Firestore rules cannot protect HTTP-triggered functions. However, if a function reads/writes Firestore based on user-provided IDs without validating ownership, it may violate BOLA/IDOR (OWASP API Top 10:2023 #4). For example:
// VULNERABLE RULE in firestore.rules
match /users/{userId}/messages/{msgId} {
  allow read: if request.auth != null; // But function uses admin SDK bypassing this
}
// The function may still expose other users' messages if it uses req.query.msgId
  • Event Source Validation Gaps: Verify that functions triggered by Firestore events (e.g., onCreate) are not also exposed via HTTP. If they are, ensure the HTTP version checks the firebase-auth header or X-Firebase-GCheck (App Check) header.
  • Data Exposure in Responses: Test if the endpoint returns full document snapshots. Use a tool like middleBrick to submit the function URL. The scanner will flag unauthenticated endpoints and analyze responses for PII, API keys, or excessive data. For instance, a response like { "doc": { "email": "user@example.com", "ssn": "123-45-6789" } } indicates Data Exposure (OWASP API Top 10:2023 #8).

Scanning with middleBrick: Submit the Cloud Function URL (e.g., https://us-central1-project.cloudfunctions.net/syncToExternal) to the web dashboard or CLI (middlebrick scan <url>). The scanner tests for missing authentication, input validation flaws (e.g., does it accept arbitrary document paths?), and data leakage in responses. It also cross-references any OpenAPI spec you provide to see if the endpoint is documented as requiring auth.

Firestore-Specific Remediation

Fix webhook abuse in Firestore by securing the Cloud Function layer and validating event authenticity:

  1. Enforce Firebase App Check for HTTP Triggers: App Check ensures requests come from your registered apps (web, iOS, Android). For HTTP functions, validate the App Check token:
const { initializeApp } = require('firebase-admin/app');
const { getAppCheck } = require('firebase-admin/app-check');

initializeApp();

exports.secureSync = functions.https.onRequest(async (req, res) => {
  const appCheckToken = req.get('X-Firebase-GCheck');
  if (!appCheckToken) {
    return res.status(401).send('Missing App Check token');
  }
  try {
    await getAppCheck().verifyToken(appCheckToken);
  } catch (error) {
    return res.status(401).send('Invalid App Check token');
  }
  // Now process req.body, but still validate structure
  const expectedSchema = { after: { fields: { /* ... */ } } };
  // ... rest of logic
});
  1. Validate Firestore Event Structure: If the function is triggered by Firestore (onCreate), do not also expose it via HTTP. If you need an HTTP endpoint, separate concerns: one function for Firestore triggers (no HTTP), another for webhooks with strict schema validation. Use a library like ajv to validate the incoming payload against a JSON schema that matches Firestore's event format.
const Ajv = require('ajv');
const ajv = new Ajv();
const firestoreEventSchema = {
  type: 'object',
  properties: {
    before: { type: ['object', 'null'] },
    after: { type: 'object' },
  },
  required: ['after'],
};

exports.validatedWebhook = functions.https.onRequest(async (req, res) => {
  const valid = ajv.validate(firestoreEventSchema, req.body);
  if (!valid) {
    return res.status(400).json({ error: 'Invalid event format', details: ajv.errors });
  }
  // Proceed with req.body.after
});
  1. Restrict Firestore Access in Functions: Even with admin privileges, functions should not expose all data. Use document-level checks:
exports.userSpecificAction = functions.https.onCall(async (data, context) => {
  // For callable functions, context.auth is available
  if (!context.auth) {
    throw new functions.https.HttpsError('unauthenticated', 'Auth required');
  }
  const userId = context.auth.uid;
  const docSnap = await admin.firestore().collection('users').doc(userId).get();
  // Only return data the user owns
  return { email: docSnap.data().email };
});
  1. Use Security Rules to Limit Function Access: While rules don't apply to admin SDK, you can restrict which documents a function can access by using a service account with limited permissions. Create a custom IAM role for the Cloud Function's service account that only allows datastore.entities.get on specific collections.

Additionally, monitor logs for unexpected function invocations. Set up Cloud Audit Logs to alert on google.cloud.functions.v1.CloudFunctionsService.UpdateFunction or high-volume calls to the endpoint.

For continuous validation, integrate middleBrick into your CI/CD pipeline via the GitHub Action. On every pull request, scan new or modified Cloud Function URLs to ensure they meet authentication and data exposure checks before deployment.

Frequently Asked Questions

How is a Firestore trigger different from an HTTP webhook, and does middleBrick scan both?
A Firestore trigger (e.g., functions.firestore.document('users/{id}').onWrite(...)) is invoked automatically by Firestore events and has no public URL. An HTTP webhook is a separately deployed Cloud Function with functions.https.onRequest that accepts public POST requests. middleBrick scans any accessible URL, so it can test HTTP-triggered functions but cannot directly scan Firestore triggers since they lack an endpoint. However, if you expose a Firestore-triggered function's logic via an HTTP wrapper, middleBrick will scan that wrapper endpoint for authentication and data exposure flaws.
Can Firestore security rules prevent webhook abuse on Cloud Functions?
No. Firestore security rules apply only to direct Firestore database access (via client SDKs or REST). Cloud Functions using the Admin SDK bypass these rules because they run with elevated privileges. To prevent webhook abuse, you must secure the HTTP endpoint itself using Firebase App Check, ID token verification, or custom token checks inside the function. Firestore rules can still protect the underlying data if the function uses a limited-privilege service account, but the primary defense is at the function's HTTP layer.