Driver FixRecommendedSound, Wi-Fi or graphics acting up? Check drivers firstFind missing or outdated drivers fast.Check DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix Now×
Skip to content
World desk5 min

PostgreSQL Views and RLS: Find and Fix the Wrong Policy Identity

A default PostgreSQL view applies the view owner’s privileges and RLS policies to underlying tables. Learn how security_invoker changes that behavior—and what it cannot override.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A PostgreSQL view can expose rows that a caller’s own row-level security (RLS) policy would hide. By default, PostgreSQL checks access to a view’s underlying relations using the view owner’s privileges, and applies that owner’s RLS policies to protected base tables. To make underlying permissions and policies follow the invoking user, use security_invoker = true—while also checking for RLS bypass roles and table ownership.

Why a view can show rows hidden by a caller’s policy

PostgreSQL views use a rewrite mechanism to incorporate the view’s query into the caller’s query. By default, privileges on underlying relations are checked using the view owner’s privileges. When an underlying table has RLS enabled, PostgreSQL ordinarily applies the view owner’s policies, not the invoking user’s. If the owner’s policy context permits rows the caller’s policy would reject, those rows may be visible through the view.

As an Amazon Associate I earn from qualifying purchases.

This is the documented default, not a rule that every view always disables RLS. PostgreSQL’s documentation states: “If any of the underlying base relations has row-level security enabled, then by default, the row-level security policies of the view owner are applied, and access to any additional relations referred to by those policies is determined by the permissions of the view owner.” (PostgreSQL 18 CREATE VIEW documentation)

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A tenant-policy example

Suppose accounts has a policy such as USING (tenant_id = current_setting('app.tenant_id')::int), and a view over that table is owned by a role whose policy context can see every tenant’s rows. With a normal view, the base table’s RLS evaluation uses the view owner’s identity and context. A caller whose own policy would restrict results to one tenant could therefore see additional rows through the view.

The exact result depends on the policies, role attributes, ownership, and session settings in the deployment. The important audit question is not just whether RLS is enabled on the table; it is which role PostgreSQL uses when the table is reached through the view.

Choose the view option that matches the security boundary

View configuration Underlying privileges and RLS identity What it is for Caller permissions
Default view View owner Lets the view operate on underlying relations using the owner’s privileges Callers generally need permission to use the view; underlying relation access is checked with the owner’s privileges
security_invoker = true Invoking user Makes underlying relations use the caller’s privileges and policies, as if referenced directly in the query The caller also needs the relevant underlying relation privileges

To have the caller’s own table privileges and RLS policies govern access through a view, create or alter it with security_invoker = true. For example:

CREATE VIEW tenant_accounts WITH (security_invoker = true) AS
SELECT account_id, tenant_id
FROM accounts;

For an existing view, the corresponding option can be changed with ALTER VIEW:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
ALTER VIEW tenant_accounts SET (security_invoker = true);

Grant callers the underlying table privileges they need as well as permission to access the view. If they lack those base-relation privileges, a security-invoker view may fail rather than provide the intended result. See the CREATE VIEW documentation for the version-specific syntax and behavior.

Do not confuse security_invoker with security_barrier

security_invoker controls whose permissions and RLS policies apply to underlying relations. security_barrier addresses a different concern: it affects predicate evaluation order to guard against information leaks through unsafe expressions. It does not switch policy evaluation from the view owner to the caller.

Option Controls Does not do
security_invoker Identity used for underlying relation privileges and RLS Override superuser, BYPASSRLS, or table-owner bypass rules
security_barrier Predicate ordering and protection against certain expression-based information leaks Change which role’s RLS policies apply

Setting security_barrier alone is not a fix for a view that uses the wrong policy identity. The PostgreSQL documentation describes these options separately in its CREATE VIEW reference.

Check RLS bypass rules even with a security-invoker view

A caller-based view does not cancel PostgreSQL’s general RLS bypass rules. Superusers and roles with the BYPASSRLS attribute bypass RLS. A table’s owner normally bypasses policies on that table too. If the table owner should be subject to RLS, use ALTER TABLE ... FORCE ROW LEVEL SECURITY; this changes the table-owner case, not the superuser or BYPASSRLS exceptions.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

These rules apply to the role PostgreSQL uses to reach each table. In a default view, that may be the view owner; with security_invoker = true, it is the invoking user. Check both roles’ attributes and their relationship to every protected table. PostgreSQL’s row security documentation explains the bypass behavior.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Audit an existing view and its dependencies

  1. Identify the view owner. Check who owns the view, because the owner’s privileges and policy context govern underlying relations by default.
  2. Inspect the view options. Determine whether security_invoker and security_barrier are set. Treat them as separate controls with different purposes.
  3. Inspect every base table. Confirm whether RLS is enabled and review the policies that apply to relevant roles. Include relations referenced by policy expressions.
  4. Check role attributes and table ownership. For the view owner and intended callers, check superuser and BYPASSRLS status, and determine who owns each protected table.
  5. Check FORCE ROW LEVEL SECURITY. If table-owner policy enforcement is intended, verify that the table has been configured with FORCE ROW LEVEL SECURITY.
  6. Follow nested views. Inspect views referenced by other views. An underlying security-invoker view retains caller-based checking when reached through an outer view.
  7. Verify the installed PostgreSQL version. Confirm the major and minor version before relying on syntax or assessing a release-specific security issue.

PostgreSQL 18 documentation describes the default owner-based behavior, and PostgreSQL 14 documentation already described the underlying privilege behavior; this is not a new PostgreSQL 18 change (PostgreSQL 18 CREATE VIEW; PostgreSQL 14 CREATE VIEW).

Separate the default behavior from planner security fixes

PostgreSQL 17.6 release notes describe CVE-2025-8713, a specific planner-time permission-check issue: a view owner’s permissions could satisfy an initial security check before a leaky function was applied to underlying table statistics. The fix moved view security checks to the start of planning. That issue is distinct from the ordinary rule that a default view uses its owner’s RLS policies for underlying tables. Consult the PostgreSQL 17.6 release notes and verify the installed release when evaluating exposure.

PostgreSQL 11.3 release notes also document a historical RLS bypass involving selectivity estimators. That separate fix illustrates that planner interactions can create their own security issues; it is not the explanation for the normal view-owner policy behavior described above (PostgreSQL 11.3 release notes).

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.