flutterfirebasegoogle-cloud-platformfirebase-authenticationgoogle-cloud-functions

Why can anyone call my Firebase callable Cloud Function via its HTTPS URL, outside my mobile app?


I have a Firebase project with a mobile app (Flutter) that uses callable Cloud Functions. From the app, I invoke them with the Firebase SDK like this:

const functions = firebase.functions();
const callable = functions.httpsCallable('myFunctionName');
callable({ someData: 'value' }).then(result => {
  console.log(result.data);
});

I assumed that onCall functions could only be invoked by my app’s authenticated clients. However, I discovered I can call the underlying HTTPS endpoint directly from a browser or Postman using the URL. It still executes—even when not called from my app.

In my Python Cloud Function, I’ve already added this authentication check:

if not req.auth or not req.auth.uid:
    return {"status": 400, "message": "User not authenticated"}

Because of this check, an unauthenticated caller can’t run the actual function logic. However, the request still causes the function instance to spin up (cold start), meaning it consumes resources and could be abused for a DoS-style cost attack.

I’ve also enabled App Check, so legitimate app clients must pass verification — but the HTTPS endpoint still remains publicly reachable.

Config observation: In Google Cloud Console → Cloud Functions → Permissions, I see:

Authentication: Require authentication
Warning: This service is publicly accessible because 'allUsers' has been granted permission on the service.

Does this IAM setting explain why the endpoint is still publicly accessible? If I remove allUsers from the IAM policy, will it block all external requests before they spin up the function, so only authenticated users from my app can call it?

An onCall request includes a Firebase Authentication user ID token for the logged-in user making the request. The backend automatically verifies this token and provides it in the handler's context. If the token is invalid, the request is rejected. However, I find it odd that my billable container instance count still reaches 1.

Did see a similar question here : but does not have a solution : How do you make a HTTPS onCall Cloud Function deployed via Firebase private


Solution

  • I assumed that onCall functions could only be invoked by my app’s authenticated clients.

    That's definitely not true.

    the request still causes the function instance to spin up (cold start), meaning it consumes resources and could be abused for a DoS-style cost attack.

    That's always the risk when providing services that are accessible from anywhere in the world. There is no 100% reliable way of eliminating this risk.

    I’ve also enabled App Check, so legitimate app clients must pass verification — but the HTTPS endpoint still remains publicly reachable.

    App Check doesn't shut down access to a function from the public, nor does it provide 100% accurate protection. This is even stated in the documentation:

    App Check relies on the strength of its attestation providers to determine app or device authenticity. It prevents some, but not all, abuse vectors directed towards your backends. Using App Check does not guarantee the elimination of all abuse, but by integrating with App Check, you are taking an important step towards abuse protection for your backend resources.

    Unfortunately, if you want to run a public app with a backend, you're going to have to accept that an attacker can incur some costs, as is the case with all public apps and services running on any cloud platform.

    Does this IAM setting explain why the endpoint is still publicly accessible? If I remove allUsers from the IAM policy, will it block all external requests before they spin up the function, so only authenticated users from my app can call it?

    No. If you remove allUsers, your app will not be able to invoke your callable function at all, and your client will always receive an authentication error. Your function must have allUsers in order to function correctly. GCP IAM setting are for controlling access to cloud resources using GCP service accounts, not Firebase users. Firebase users have nothing at all to do with GCP allUsers - they refer to completely different things.

    If you want strongly enterprise-grade protection, you'll have to look into paying for and configuring a product such as Cloud Armor, which can further help with abuse.

    See also: