OneShot

All packsMulti-Tenant Auth & RBAC CoreSolve

postgres column level grants restrict role escalation

Table-level UPDATE grants let an admin rewrite an invite's role

A plain UPDATE grant on invites lets any permitted caller change the invited role, not just revoke the invite -- column-level grants narrow that to exactly one field.

3 of 3 runs passedOne decision inside Multi-Tenant Auth & RBAC Core (nextjs-postgres).

What goes wrong

If the app role has a blanket UPDATE grant on the invites table, then any code path allowed to revoke a pending invite is also, technically, allowed to rewrite that invite's target role, email, or token -- an admin who should only be able to cancel an admin-level invite someone else sent could instead quietly upgrade a pending member invite to an admin invite by writing to a column nothing in the app's own logic intended to expose.

Why agents get it wrong

A table-level GRANT is the default unit most ORMs and tutorials reach for -- "this role can update this table" -- and application-level checks (only allow revoking, never editing) look sufficient because they gate every code path the app actually calls. What they don't gate is a bug or a future code path that forgets to restrict itself, and Postgres itself doesn't stop that write if the grant is table-wide.

What Multi-Tenant Auth & RBAC Core pre-decides

Core decision 11 grants app_user UPDATE only on invites.revoked_at and only on org_members.role -- not the whole row. An admin can revoke any pending invite, including one an owner sent, but nothing can rewrite an invite's role, email, or token; and re-pointing a membership's user_id or org_id is a 42501 permission error before any RLS policy even runs, closing off the escalation path at the grant level, not just the application level.

Source: ARCHITECTURE.md core decision 11

Coming soon — $149Full receipt and details for Multi-Tenant Auth & RBAC Core

Related problems