Incident Review: The Arc Browser Vulnerability

How you can prevent Firebase misconfiguration
AUTHOR
Chris Reuter
PUBLISH DATE
September 27, 2024

Earlier this month, a vulnerability in the Arc browser was announced by security researcher xyz3va and The Browser Company (makers of Arc). In short, custom CSS or JavaScript could be executed in any user’s browser. Obviously injecting malicious code into a web browser is a catastrophic failure, and the world quickly reacted to the root cause: misconfigured Firebase.

Arc browser has a feature called Arc Boosts, which allows users to run their own CSS or JS on any website. Boosts have a variety of interesting use cases (adding functionality, changing appearance, trolling, etc.), but the most interesting aspect of Boosts before August 25th, 2024 was its implementation.

To quote xyz3va:

arc boosts can contain arbitrary javascript

arc boosts are stored in firestore

the arc browser gets which boosts to use via the creatorID field

we can arbitrarily change the creatorID field to any user id

The real problem was with how Firebase was configured. From The Browser Company:

We use Firebase as the backend for certain Arc features (more on this below), and use it to persist Boosts for both sharing and syncing across devices. Unfortunately our Firebase ACLs (Access Control Lists, the way Firebase secures endpoints) were misconfigured, which allowed users Firebase requests to change the creatorID of a Boost after it had been created. This allowed any Boost to be assigned to any user (provided you had their userID), and thus activate it for them, leading to custom CSS or JS running on the website the boost was active on.

So the culprit is Firebase ACLs…but there is more to the story.

Firestore Rulesets

The tale might have ended there, if not for some research from whoever owns venki.dev. In their analysis published on September 22nd, they identified that most official documentation for Firestore featured are vulnerable-by-default ACLs (the exact opposite of secure-by-default). [Side note, venki.dev has some good looking recipes on their site]

Venki goes on to note:

You should expect that many Firestore applications online right now would allow you to create an arbitrary doc on the behalf of another user.

So you’re (potentially) sitting on a time bomb if you’re using Firestore and you weren’t intimately familiar with Firestore rulesets when you created your database. How can you both remediate your vulnerable applications and stop this from happening in the future?

Secure-by-default Firestore rulesets for Terraform users

The below is specific to Terraform shops. Venki’s advice is general-purpose and can be adapted to your specific scenario, however you are deploying Firestore.

Without Resourcely

First, I’ll point you in the right direction like any good human would do. If you want to spend your time manually fixing these vulnerabilities, and build your own paved path to deploying Firestore (with a Terraform module, or similar), you’ll want to use Venki’s blog. They have the correct code there, and a test to identify if you have this vulnerability.

  1. Add the change owner of doc denied function to your test suite
  2. Identify where the vulnerability exists
  3. Scope whether the behavior is intended or not
  4. Add the new update rule to your existing Firestore databases

Then, you’ll need to adjust your Terraform module(s) with the updated rule for any future Firestore deployment. Watch out for forks, or changes by developers - you’ll be stuck watching every Terraform PR, forever, monitoring for this behavior.

Resourcely has a way!

Resourcely Blueprints, Guardrails, and Campaigns can help fix what is broken and prevent this and other vulnerabilities from ever making it to production.

Blueprints

Creating a Blueprint will give your team a guided experience for deploying Firestore that meets your expectations (including not allowing the offending ruleset). When you create a Blueprint, a hosted form is automatically created for use by developers to deploy Firestore. When they use the Blueprint, Terraform is generated and a PR is submitted to your existing change management.

Here’s a secure-by-default Blueprint for Firestore:


---
constants:
  __name: "{{ name }}_{{ __guid }}"
  __project_name: "{{ project_name }}_{{ __guid }}"
variables:
  name:
   desc: "Database name"
  project_name:
   desc: "Project name"
---
resource "google_firestore_database" "{{ __name }}" {
  name        = {{ __name }}
  location_id = {{ location | desc: "Region, defaults to us-east1" | default: "us-east1" }}
  type        = {{ type }}
}

resource "google_firebaserules_ruleset" "{{ __name }}" {
  source {
    files {
      content = "service cloud.firestore {match /databases/{{__name}}/documents { match /{document=**} { allow read, delete: if request.auth != null && request.auth.uid == resource.data.owner_uid allow update: if request.auth != null && request.auth.uid == resource.data.owner_uid && request.auth.uid == request.resource.data.owner_uid allow create: if request.auth != null && request.auth.uid == request.resource.data.owner_uid }}}"
      name    = "firestore.rules"
    }
  }

  project = {{ __project_name }}
}

resource "google_firebaserules_release" "{{ __name }}" {
  name         = "cloud.firestore"
  ruleset_name = "projects/{{ __project_name }}/rulesets/google_firebaserules_ruleset.{{ __name }}.name}"
  project      = {{ __project_name | links_to: resource.google_firebaserules_ruleset.project  }}
}

This creates a Cloud Firestore database with an accompanying ruleset (thanks to Venki!) that locks down access to the database. It also makes a release to apply the ruleset to the Cloud Firestore.

This Blueprint automatically generates a form for developers to use like this:

Filling out this form and submitting it would result in the following (safe) Terraform being submitted as a PR:


resource "google_firestore_database" "database_name_fraMshbmm94dxGRa" {
  name        = "database_name_fraMshbmm94dxGRa"
  location_id = "us-east1"
  type        = "DATASTORE_MODE"
}

resource "google_firebaserules_ruleset" "database_name_fraMshbmm94dxGRa" {
  project = "my_project_fraMshbmm94dxGRa"

  source {
    files {
      content = "service cloud.firestore {match /databases/database_name_fraMshbmm94dxGRa/documents { match /{document=**} { allow read, delete: if request.auth != null && request.auth.uid == resource.data.owner_uid allow update: if request.auth != null && request.auth.uid == resource.data.owner_uid && request.auth.uid == request.resource.data.owner_uid allow create: if request.auth != null && request.auth.uid == request.resource.data.owner_uid }}}"
      name    = "firestore.rules"
    }
  }
}

resource "google_firebaserules_release" "database_name_fraMshbmm94dxGRa" {
  name         = "cloud.firestore"
  ruleset_name = "projects/my_project_fraMshbmm94dxGRa/rulesets/google_firebaserules_ruleset.database_name_fraMshbmm94dxGRa.name}"
  project      = "my_project_fraMshbmm94dxGRa"
}

We’re using a couple of Blueprint QoL features here, including appending the constant __guid, linking resources together, adding descriptions and defaults, and more.

Guardrails

Let’s say that you wanted to put a backstop in place, just in case someone tried to apply a different ruleset without knowing they were opening up their Firestore to public access. This is where Guardrails, policies that safeguard your cloud infrastructure, come in handy.

Guardrails are integrated both into the configuration process (at the time of Blueprint PR creation), as well as during your CI pipeline. We could implement the following two Guardrails:


GUARDRAIL "Disallow read/write access for all users for Firestore"
 WHEN google_firebaserules_ruleset
  REQUIRE source.files.content NOT MATCHES REGEX "\ballow read, write: if true\b"
  
GUARDRAIL "Disallow any logged-in user has read and write access to entire Firestore database"
 WHEN google_firebaserules_ruleset
  REQUIRE source.files.content NOT MATCHES REGEX "\ballow read, write: if request.auth.uid != null\b" 

These Guardrails check to see if Firestore rulesets contain specific fragments that are unsafe, such as allowing read/write access to all users.

In our previous Blueprint, we didn’t make the Firestore ruleset an input field editable by users - we didn’t want to allow developers to deviate from our recommended ruleset. If we had, the Guardrail would prevent the developer from implementing an unsafe rule at time of configuration:

If a developer changed the Terraform after the fact and circumvented a Blueprint, our Guardrails would still catch this unwanted behavior and flag it for approval as part of CI.

Campaigns (early access)

Finally, Campaigns are an early access Resourcely feature that simplify remediation of vulnerabilities that exist in production. If you have a Firebase configuration that is unsafe, you could fix that by running a Campaign. Simply define the offending behavior (as we have with the Guardrails above), and specify the proper configuration.

Resourcely Campaigns will automatically track the offending instances, create PRs, and submit them via your change management. Developers and other interested parties will have a chance to review the fixes, just in case the configuration was intended at the time of creation.

To get early access to Campaigns, let us know!

Conclusion

We’ve seen Firebase configuration be the cause of many-an-incident recently. Unsurprisingly, Firebase isn’t really the culprit - bad documentation combined with DevOps practices have resulted in developers with limited understanding of cloud services who are asked to configure and deploy those services.

While The Browser Company announced they would be moving off of Firebase, we don’t think that is a real fix to a systemic problem. Instead, DevOps, SRE, and platform teams should be working to proactively ease the configuration of services like Firebase while putting backstops in place that prevent bad configuration from ever making it into production.

This is why we built Resourcely, and why we won’t stop until common misconfiguration like this is defeated.

We hope this helps! If you’re interested in using Resourcely, you can sign up here.

Ready to get started?

Set up a time to talk to our team to get started with Resourcely.

Get in touch

More posts

View all
September 25, 2024

Embracing the Configuration Platform

The next wave of DevOps
July 16, 2024

Why we built Resourcely

Solving the misconfiguration problem
July 30, 2024

Guardrails: Scalable policies for cloud infrastructure

Safeguard the security and stability of your cloud

Talk to a Human

See Resourcely in action and learn how it can help you secure and manage your cloud infrastructure today!