Squanchy and Firestore rules — a post-mortem

We got a bunch of warnings across several Firebase instances using Firestore…

Post-mortem

First, a bit of background. Squanchy’s Firestore instance stores data with this structure:

A typical Firestore structure for Squanchy
a        // Allow everything in here (document=**), except...
├── b // Do not allow anyone (allow read,write: if false)
├── c // Do not allow anyone (allow read,write: if false)
├── d
└── e
service cloud.firestore {  match /databases/{database}/documents {
match /a/{document=**} {
allow read: if true;
}
match /a/b/{document=**} {
allow read: if false;
}
match /a/c/{document=**} {
allow read: if false;
}
}
}

If you give access to any resource you cannot revoke it with another rule.

The blanket rule that allows reads from /a/{document=**} is the one that wins here: everyone can read anything inside /a/
service cloud.firestore {  match /databases/{database}/documents {
match /a/c/{document=**} {
allow read: if true;
}
match /a/d/{document=**} {
allow read: if true;
}
}
}
You can see the rules now will deny access to /a/b/ as we wanted.

What about Squanchy’s Firestore instance?

These were our default Firestore rules:

Reading data in raw_data was permitted… bad!
But at least they couldn’t write to it.
Anyone could read other users’ favourites…
…but not add/change/remove them.

Corrective actions

Our corrective action was to patch the rules with the following:

No access to raw_data.
Anyone can read /views/schedule…
…but nobody can write to it (that is with my account).
I can read/write my own favourites…
…but not someone else’s.

Security issue impact

We’ll be honest, here — we don’t know. It’s not that we don’t want to know or don’t care; it’s simply impossible to know, since Firestore keeps zero access logs. While we doubt anyone took advantage of this while it was live (it’s since been patched out in all instances of Squanchy and forks we know were affected), there is still a remote possibility some PIIs of speakers and CfP submitters were leaked. This should only be impacting Droidcon Italy 2018 and 2019, the latter of which is not controlled by us (but has been patched by the conference organisers); other conference instances didn’t use the same raw_data structure and we had no access to any other conference’s PIIs anyway, so those aren’t affected. We’ve applied the patch to those instances as well, just in case.

Learnings

Firstly, we learnt that we had fundamentally misunderstood how Firestore access rules worked when interacting with each other. We had gotten a bunch of emails from Firestore alerting of potentially exposed data (this seems to be a common enough issue they had to put in place an automated warning for it…) but we thought it was due to some of our data being world-readable by default. We didn’t have the simulator when we wrote the rules in the first place, and when it was made available we didn’t think about testing them. Our own testing with code was also not in-depth enough to find out these issues — we simply assumed they wouldn’t need to be checked.

Acknowledgements

Thanks once again to Doug Stevenson for helping us understand that the Firestore emails weren’t just a false positive from some automated checks (we’ve seen quite a few from Google in the last few months… see Play Store) but we should’ve actually done something about it. Thanks to Daniele Conti who also figured out there were issues pretty much the next day, before I could tell him I had spoken to Doug, and who wrote and deployed the patch. Thanks to Mark Allison for his data regulation advice.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Sebastiano Poggi

Sebastiano Poggi

"It depends" 🤷‍♂️ - Google Developer Expert for Android, Flutter and Identity. A geek 🤓 who has a serious thing for good design ✨ and for emojis 🤟