How to audit a Flutter and Firebase app that stores patient data: a checklist
This is the checklist I go through when I review a Flutter app on Firebase that handles patient or health data, before a launch or a hospital pilot. It is written for the developer who built the app. Go through it with the repository and the Firebase console open. Every item is a question you can answer with yes, no or "I do not know", and "I do not know" is a finding.
The idea behind most of the items is the one from my course Securing a Flutter + Firebase app for medical data: the app only ever sees pseudonymised records, and the pseudonymisation key, kept outside the app, is the only way to link a record back to a patient. Data linkable through a separately kept key is still personal data under GDPR, so the key gets the same care as the records.
1. Firestore and Cloud Storage security rules
- Rules deny by default. No
allow read, write: if trueanywhere, and no rule that only checksrequest.auth != nullfor patient data. - A patient can read and write only documents tied to their own pseudonym. The rule compares a field in the document with a value from the token, not with something the client sends in the request.
- Staff access goes through roles in custom claims, and a nurse reads only the patients assigned to them.
- Writes validate the schema: required fields, types, no extra fields, no field that would carry a name or a national ID into Firestore.
- Storage rules follow the same model as Firestore for files such as ECG exports or photos.
- The rules have a test suite that runs on the Firebase Emulator Suite, and a release to production includes running it.
- Nobody deploys rules by hand from a laptop. They are in the repository and reviewed like code.
2. Authentication
- Sign-in methods are the ones you meant to enable. Anonymous sign-in is off unless the app needs it and the rules account for it.
- Patients and staff are distinguished by custom claims set on the server, never by a field the client can write.
- Claims are set by a Cloud Function or an admin tool that itself checks who is calling.
- Email enumeration protection is on. Password policy and multi-factor authentication are set for staff accounts.
- Sessions and refresh tokens are revoked when a staff member leaves or a device is lost, and there is a written way to do it.
3. App Check
- App Check is enabled for Firestore, Storage, Functions and any other Firebase API the app calls.
- Enforcement is on, not just monitoring, after you checked that the real app passes.
- Debug tokens exist only in debug builds and are not committed to the repository.
4. Cloud Functions and IAM
- Each Function runs as its own service account with the least permissions it needs, not as the default App Engine account with Editor.
- Callable Functions verify the caller's token and claims. HTTP Functions that must stay private are not open to
allUsers. - Secrets live in Secret Manager or Function secrets, not in environment variables committed to the repository and not in the Flutter app.
- The list of people with Owner or Editor on the project is short, named and reviewed. Service account keys as JSON files do not exist, or there is a reason for each one.
- The re-identification step, where a pseudonym is linked back to a patient, is one Function or one service outside the Firebase project, and it logs every use.
5. Data location and EU regions
- The Firestore database, Storage buckets and Functions are in EU regions. The region is set once and cannot change later, so check it now.
- The pseudonymisation key service runs in the EU too.
- Any service outside Firebase that receives data, for example a mail provider or an error tracker, is listed with its region and its role under GDPR.
6. Encryption and pseudonymisation
- Firestore holds pseudonymised records only: a pseudonym instead of a name, date of birth, national ID, phone or address.
- The pseudonymisation key is stored outside the Firebase project, access to it is limited, and every use is logged.
- Fields that must be stored but must not be readable by the backend are encrypted on the device, and the device key is in the platform keystore, not in shared preferences.
- The app does not log, cache or write to analytics anything that would let you re-identify a patient.
- A written threat model, one page, says what an attacker with full Firestore read access learns. If the answer includes a name, the model is not done.
7. Logging and audit trail
- Reads and writes of patient records by staff are logged with who, what and when, and the log cannot be edited by the people it logs.
- Logs contain pseudonyms, not names, and no request bodies with health data.
- Log retention is set and matches what the privacy notice says.
- Someone reads the logs. There is an alert for unusual access, for example one account reading many patients.
8. Backups and retention
- Firestore has scheduled backups or point-in-time recovery enabled, and a restore has been tried at least once.
- Backups are in the EU and reachable by fewer people than the live database.
- Retention periods are defined per data type, and there is a job or a procedure that deletes data when they end.
- A patient's request to delete their data has a procedure that covers Firestore, Storage, backups within their retention, and the key service.
9. Third-party SDKs
- Every SDK in
pubspec.yamlthat talks to the network is listed with what it sends and where. - Analytics, crash reporting and advertising SDKs do not receive health data, pseudonyms or identifiers you did not mean to share. Check the automatic collection settings, not only your own calls.
- Push notifications do not carry health data in the payload. The notification tells the patient to open the app; the app fetches the content.
- Each third party that processes personal data has a data processing agreement and appears in the records of processing.
10. GDPR basics
- The lawful basis for processing health data is written down, including the Article 9 condition.
- There are records of processing activities that list the data, the purposes, the recipients, the regions and the retention.
- You have decided whether a data protection impact assessment (DPIA) is needed, and written down why. For an app processing health data at scale, expect that it is.
- The privacy notice matches what the app does, including the third parties from section 9.
- Patients can get a copy of their data and ask for deletion, and both work end to end.
- If you exchange records with a hospital system over HL7 FHIR, patient identity stays on the hospital side and your app keeps using the pseudonym.
What to do with the result
Order the "no" and "I do not know" answers by what an attacker with Firestore read access would get from each, and fix in that order. Sections 1, 6 and 4 usually come first.
If you want this done by someone who has not seen the code before, with a written report and a call: security and GDPR audit of a Flutter and Firebase medical app, a fixed package of 12 h for 2 580 PLN net, report within 7 working days. It is a read-only review of the same areas as this checklist, not a penetration test, not a certification and not a legal opinion.