A profile screen that only shows display name and bio looks like it keeps the role field safe. Firestore rules never see that screen; they evaluate the document a request proposes. Anyone signed in can send role: "admin" to their own profile document, and an ownership-only rule allows it.
The fix is a field allowlist, split in two. On update, allow the write only when diff(
resource.data).affectedKeys() stays inside the editable fields. On create there is nothing to compare against, so that path validates the whole payload with keys().hasOnly().
The tempting shortcut is one allow write carrying that diff check. Role edits are blocked and existing users can still rename themselves, so an update-only test suite stays green, while every new account's first profile write fails: resource is null and the condition errors out.
Role itself belongs to server code, with rules reading a custom claim instead of a field the client can write. Full rule set, the emulator cases that catch both failures, and what field rules cannot do:
https://www.duskolicanin.com/blog/flutter-firestore-rules-field-allowlist