PostgreSQL Row-Level Security (RLS) is a database authorization layer, not a replacement for authentication or application authorization. PostgreSQL first applies ordinary SQL privileges such as GRANT; when RLS is enabled, policies then decide which rows a normal role can see or modify. If RLS is enabled and no applicable policy exists, PostgreSQL uses default deny. Two production details are easy to miss in AI-built apps: table owners normally bypass RLS unless FORCE ROW LEVEL SECURITY is used, and superusers or roles with BYPASSRLS always bypass it. That means tests performed only with an owner, admin, migration role or service credential can falsely suggest that tenant isolation is correct. In August 2026 PostgreSQL also fixed CVE-2026-14666, where cached row-security plans could keep stale permissions after role or ownership changes. Upgrade affected supported branches to the fixed releases, test with the same runtime role the app uses, enforce object-level authorization in the API, and keep database permissions least-privileged.
An AI-built multi-tenant app filters by tenant_id in code but has no database policy preventing another tenant's rows from being returned
Queries work in the SQL editor or migration connection but fail or behave differently for the real application role
A table has RLS enabled but the team cannot explain which SELECT, INSERT, UPDATE and DELETE policies apply to each runtime role
Tests use the table owner or a service/admin credential, so they never exercise the same RLS path as ordinary users
A user can change a record ID in an API request and the server fetches the row before verifying ownership or tenant membership
The PostgreSQL estate is on a version affected by CVE-2026-14666 and role membership or database ownership can change while pooled sessions remain active
Possible causes
Authentication, API authorization, SQL privileges and row-level security were collapsed into one vague 'user is logged in' check
The application relies on client-supplied tenant or object IDs without a server-side ownership/relationship check
RLS was enabled without a complete policy matrix for read and write operations
The production connection uses a table owner, superuser, service role or BYPASSRLS-capable role that bypasses intended tenant policies
Developers validated policies in an elevated console rather than impersonating or connecting as the actual runtime role
A vulnerable PostgreSQL version can reuse a cached row-security plan after privilege-related role or ownership changes
HOW TO FIX IT
Work from the safest step to the harder repair.
Step 1. Write the access model before editing policies. For each table, list the runtime identities and the exact operations they need: SELECT, INSERT, UPDATE and DELETE. Record which column or relationship establishes tenant membership or ownership. Do not let an AI coding tool infer this model from UI labels or route names.
Step 2. Separate authentication, application authorization and database authorization. Authentication establishes identity; the API must still authorize the requested action and exact object; PostgreSQL privileges and RLS then constrain what the database role can do. Defense in depth is strongest when each layer has an explicit responsibility.
Step 3. Apply least-privilege SQL grants first. PostgreSQL documents RLS as an additional restriction on top of the ordinary privilege system, not a grant mechanism. A role still needs the underlying table privileges required for its job, and it should not receive unrelated schema, table or administrative privileges merely to make a query succeed.
Step 4. Enable RLS on tables that require row isolation and define explicit policies for the operations and roles that need access. PostgreSQL says that once RLS is enabled, normal row access must be allowed by policy; if no applicable policy exists, default deny applies. Treat a sudden empty result as an authorization signal to diagnose, not a reason to disable RLS.
Step 5. Design read and write rules separately. A SELECT policy that lets a user see a row is not automatically proof that the same user should be allowed to insert a new row, transfer ownership, change tenant_id, or delete the record. Review USING and WITH CHECK behavior for the exact commands your application performs.
Step 6. Test with the real runtime role. PostgreSQL table owners normally bypass RLS, and superusers plus roles with BYPASSRLS always bypass it. If application tests run only as the table owner, migration role or administrative service credential, they can completely miss the row boundary ordinary users depend on.
Step 7. Decide deliberately whether FORCE ROW LEVEL SECURITY is appropriate for owner-executed application queries. PostgreSQL allows a table owner to be made subject to row security with ALTER TABLE ... FORCE ROW LEVEL SECURITY. Do not apply this mechanically to migrations or maintenance jobs; first map which connections are supposed to bypass policies and why.
Step 8. Keep object-level authorization in the API even when RLS exists. OWASP's API Security guidance says every endpoint receiving an object identifier should verify that the logged-in user may perform the requested action on that exact object. RLS can stop many accidental cross-tenant reads, but it should not be the only place your business authorization model exists.
Step 9. Add negative tests: authenticated wrong tenant, wrong owner, wrong role, direct object-ID substitution, insert with another tenant_id, update attempting to move a row between tenants, delete of another user's record, and elevated-service paths. Make those tests fail closed and keep them in CI.
Step 10. Patch PostgreSQL for CVE-2026-14666 if the estate is affected. PostgreSQL says versions before 18.6, 17.11, 16.15, 15.19 and 14.24 are affected. Upgrade to a fixed release in the supported branch, verify the deployed server version, recycle or validate connection pools according to the normal maintenance plan, and rerun role-change/RLS regression tests.
Step 11. Audit role and ownership changes as security-sensitive events. Because database ownership, inherited role membership and BYPASSRLS can change the effective authorization boundary, document who can grant roles, change owners, create policies or use service credentials. Keep those capabilities out of browser code and ordinary AI-agent tool access.
Step 12. Verify production with a role matrix after every schema, auth-provider, tenant-membership, connection-pool or permission change. Record the server version, runtime role, enabled RLS tables, policy names and representative allowed/denied tests so a later code-generation pass cannot silently widen access.
Need the actual code? Go to GenesisCodeDoctor.com to search the Code Store or request code for the exact platform, error, and repair you are working on.
1. Does the request require protected data? If no, serve only the intentionally public representation. If yes, establish authenticated identity.
2. Can the API prove the requested action is allowed for this identity, tenant and exact object? If no, deny before returning protected data.
3. Does the runtime database role have only the SQL privileges required for this operation? If no, reduce privileges or split roles.
4. Is RLS enabled on a row-isolated table and is an applicable policy present for this operation? If no, keep access denied until the policy model is explicit.
5. Is the connection an owner, superuser or BYPASSRLS role? If yes, do not use its successful result as evidence that ordinary-user RLS works.
6. Is the PostgreSQL version fixed for CVE-2026-14666 on the branch you run? If no, patch before relying on role-change behavior in production.
REPAIR FLOW
A visual path from symptom to verified production.
Observe→
Protect→
Isolate→
Repair→
Test→
Publish→
Verify live
BEFORE YOU PASTE CODE
Protect the working site first.
Make permission and RLS changes through reviewed migrations with a rollback/recovery plan and a test role that cannot bypass RLS.
Keep database passwords, service-role secrets, connection strings and production tokens out of prompts, client bundles, logs and example code.
Use synthetic tenant data for cross-tenant authorization tests so security validation does not expose real customer records.
STOP AND GET HELP WHEN
Do not turn a repair into a larger outage.
Do not disable RLS just because an insert, update or query is blocked; diagnose the exact role, grants and policy first.
Do not run a public browser client with a PostgreSQL owner, superuser, BYPASSRLS role or other credential that can ignore tenant policies.
Do not assume UUIDs or unguessable record IDs are authorization; OWASP requires an access decision for the requested object.
Do not use a successful query from an admin console or migration role as proof that ordinary users are correctly isolated.
Do not leave an affected PostgreSQL branch unpatched after relying on role changes or row-security policies as a production control.
HOW GENESIS HANDLES IT
Diagnose the exact failure before choosing a repair.
Genesis separates the visible symptom from the underlying technical cause. Run the supported diagnostic first, review the evidence, and then use a matching repair only when the failure is actually verified.
No. RLS is a database authorization boundary. The API should still authenticate the caller and verify permission for the requested action and object; OWASP specifically recommends object-level authorization checks for endpoints that receive object IDs.
What happens if RLS is enabled but there is no policy?
PostgreSQL says a default-deny policy applies for normal row access, so rows are not visible or modifiable unless an applicable policy allows the operation.
Do table owners follow RLS policies?
Normally no. PostgreSQL says table owners typically bypass row security, though ALTER TABLE ... FORCE ROW LEVEL SECURITY can make the owner subject to it. Superusers and BYPASSRLS roles always bypass RLS.
Which PostgreSQL versions fixed CVE-2026-14666?
PostgreSQL lists the August 13, 2026 fixes as 18.6, 17.11, 16.15, 15.19 and 14.24. Earlier releases in those branches are affected.
Why did RLS work in my editor but fail in the app?
Editors and migration tools often connect with elevated roles or table owners that can bypass RLS. Reproduce the query as the same runtime role and authenticated context used by the application.
Start with a free diagnostic. If Genesis verifies a problem and a compatible treatment exists, continue to the matching Code Store product or repair path. If you cannot find the exact code you need, request it at GenesisCodeDoctor.com rather than forcing a generic snippet into the wrong platform.