Skip to main content

SEC.RLS.OWNER_UNRESTRICTED — The table's owner is exempt from its policies

  • Category: security
  • Severity: medium
  • Level: 0
  • Confidence: deterministic
  • Downtime class: none — the finding is about a table's state, not about a statement
  • Stability: stable
  • Suites: audit
  • Applies to: PostgreSQL 18

The same missing word, seen from the other side​

ENABLE ROW LEVEL SECURITY without FORCE exempts the table's owner. The connection SQLens audited with is restricted by your policies exactly as intended — the owner is not, and somebody uses that role: migrations, a maintenance command, a console session, the deploy pipeline. Each of those reads and writes across tenants with no policy consulted and nothing reported.

Why medium here and high there​

Not because the mechanism is weaker — it is identical — but because of who reaches it. SEC.RLS.NOT_FORCED fires when the exemption applies to the connection your application serves requests with, so ordinary traffic bypasses the isolation. This one fires when it applies to a role a person or a job uses deliberately: a smaller and more supervised surface.

A run whose reading could not establish which role it connected as reports through this rule — the weaker claim is the one that stays true when the stronger cannot be checked.

Bad​

ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON orders
USING (tenant_id = current_setting('app.tenant')::uuid);
-- `orders` is owned by app_owner; your web connection is app_readwrite

Good​

ALTER TABLE orders FORCE ROW LEVEL SECURITY;

Then give the migration role a deliberate way through if it needs one — a policy TO app_owner USING (true) is reviewable, where an implicit exemption is not.

SEC.RLS.NO_POLICY covers a table with RLS on and no policy at all; neither FORCE rule speaks about that state.