Firebase Security Fundamentals
Every application built on Firebase that we've looked at has had the same vulnerabilities. These common vulnerabilities aren’t hard to prevent but they're easy to overlook.
If you’re a new developer building your first Firebase app and thinking about security or you're a penetration tester who’s come across a Firebase application during an engagement, this article is for you.
Firebase is a group of cloud based services offered by Google. Most people describe the platform as a Backend as a service.
Why is Firebase Security Different?
In a traditional web application, your backend server enforces access control.
For example, in a to-do app you may want to prevent users from reading other people's to-do items, the backend code might perform a check to make sure that the requested todo_id actually belongs to the requesting user:
@app.route('/todo/<todo_id>')
def get_todo(todo_id):
todo = get_todo_by_id(todo_id)
if not todo:
abort(404, "Todo not found.")
# Authorisation check: only allow access if the todo belongs to the user
if str(todo.user_id) != str(request.user.id):
abort(403, "You are not authorised to access this todo item.")
return jsonify(todo)
With Firebase, there isn’t a traditional backend server.
Instead, the database is exposed directly to the client, and access control must be enforced through Security Rules rather than server-side code.

What Security Rules are Important?
This needs to be tailored to what application use cases you need to support but generally speaking here are some sane defaults to consider:
- Users should not be able to list all documents in a collection (database table)
- This is akin to restricting users from performing a
SELECT * FROM todos;query - A list operation retrieves all documents in a collection along with the
documentIdfor each document
- This is akin to restricting users from performing a
- For a given
documentId, users should only be able to get, update, replace, or delete records that belong to themself!
A Worked Example
Here's what can happen if you don't implement any security rules.
Let's take a look at our victim - a classic todo list app.
You login, and the app lets you add and remove your own todo lists items.

Although the frontend does not provide any buttons to interact with anyone else's Todo list items, we can connect directly to underlying Firebase data store using the same SDK to try perform these actions.
Exploitation
In all Firebase apps, the firebaseConfig required by the Firebase SDK needs to be exposed.
If you search for firebaseConfig or authDomain: in the Browser dev tools you'll normally find the details we need to connect directly.

authDomain:apiKey is exposed but in Firebase projects this is expected."None of the Firebase-related APIs use an API key as authorization for calling the API. The API key passed with the API call is only used for identification of the Firebase project or app."
We can use firepwn to exploit the lack of security rules. This is a project that Project Black has contributed to.
Give it a star!
Intialise the configuration as follows (the parameters look a bit different because the tool uses the v7 SDK).

To find collection names to query we can search the Frontend code again for collection or alternatively inspect network traffic when using the app.

todos
After logging in, we can perform a list operation by performing a Get without specifying a documentId.

In this case, we're able to retrieve todo list items created by other users!

select * from todolistOverwriting/updating our victim's todo item is as simple as changing the operation to Set and specifying a documentId to update.

Firebase storage is secured the same way with security rules. In the absence of any security rules you're similarly able to retrieve all files stored in the storage and overwrite them as desired.

Implementing Security Rules
To fix our broken access control issue the solution is to check that the userId from authentication matches the userId stored in the document.
request.auth.uid == resource.data.userId
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /todos/{todoId} {
// Allow users to read and write only their own todos
allow read, write: if request.auth != null \
&& request.auth.uid == resource.data.userId;
// Allow creating todos if authenticated, only allow creating todos
// owned by the authenticated user
allow create: if request.auth != null \
%& request.auth.uid == request.resource.data.userId;
}
}
}Full example rule.
Trying the same requests now returns this error in firepwn.

Conclusion
Security controls implemented only in the frontend can always be bypassed.
By understanding this you can avoid the same vulnerabilities we see over and over in Firebase apps.
Project Black performs penetration testing in Australia. We're a CREST accredited organisation that can help you understand your gaps.