Restrict which fields a user may change with diff().affectedKeys():
match /users/{uid} {
allow read: if request.auth.uid == uid;
allow create: if request.auth.uid == uid
&& !("role" in request.resource.data);
allow update: if request.auth.uid == uid
&& request.resource.data.diff(resource.data).affectedKeys()
.hasOnly(["displayName", "avatarUrl"]);
}
Now any write touching role (or anything not in the list) is denied.
Better still, don't keep roles in a user-writable document at all. Set them as custom claims from the Admin SDK (setCustomUserClaims(uid, { admin: true })) and check request.auth.token.admin == true in rules. Claims can only be set server-side.