Row-level security, usually shortened to RLS, moves part of an access decision into the database. A policy filters or rejects rows according to the current database identity, session context, requested operation, and values in the row. The policy applies even when application code sends a broader query.
What an RLS policy controls
Read and write operations need separate attention. A policy may restrict which rows are visible while still allowing an insert with another tenant's identifier. Updates can also require one rule for selecting an existing row and another for validating its new values.
| Operation | Policy question | Failure to check |
|---|---|---|
| Select | Which rows may be returned? | Data from another scope becomes visible |
| Insert | Which new rows may be created? | Caller assigns an unauthorised owner or tenant |
| Update | Which rows and new values are allowed? | Row moves across a protected boundary |
| Delete | Which rows may be removed? | Broad query removes another scope's data |
The database needs reliable context to answer these questions. That context may come from a database role, a transaction-local value, or verified claims passed by a trusted service. A value copied from an unverified request weakens the policy even when the SQL is correct.
Where RLS assurance can fail
An audit of vibe-coded software reads the enabled policies and also traces how the application connects. A policy that works in a local console may not apply to the privileged role used by production. Migration scripts, administration tools, background workers, and connection pools may follow different paths.
The review checks:
- Policy coverage: Every tenant-owned table and operation has the intended rule.
- Role behaviour: The runtime role does not bypass enforcement unexpectedly.
- Context lifecycle: Connection pooling cannot reuse one request's tenant context.
- Write validation: Inserts and updated values remain inside the allowed boundary.
- Privileged paths: Maintenance and support access is explicit and separately controlled.
- Test realism: Tests connect with the same role and context as the application.
RLS within a wider boundary
Tenant isolation spans more than relational rows. Files, object storage, caches, search indexes, queues, analytics systems, and external services need their own controls. RLS protects the database operations covered by its policies; it does not follow data after an application copies it elsewhere.
RLS also complements object-level authorization. The application can make a clear policy decision and return a controlled denial, while the database supplies a second enforcement point against an overly broad query. The two layers should express the same ownership and tenant rules.
Evidence that policies hold
A useful test suite creates rows for multiple identities or tenants, then exercises each operation through the production database role. It verifies allowed rows, denied rows, inserts, ownership changes, bulk operations, and privileged maintenance paths. Tests should also reuse pooled connections to expose context leakage.
The audit records each protected table, policy, runtime role, context source, and bypass path. This evidence belongs in the production review of generated software, because the presence of an RLS policy alone does not prove that the running application is subject to it.