Databases 5 min read

Understanding PostgreSQL Function Security: Definer vs Invoker Explained

This article explains how PostgreSQL functions can be defined with security definer or security invoker, details the differences between session_user and current_user, demonstrates setting roles and search_path, and provides practical examples and safeguards to prevent privilege escalation.

dbaplus Community
dbaplus Community
dbaplus Community
Understanding PostgreSQL Function Security: Definer vs Invoker Explained

Function Security in PostgreSQL

PostgreSQL functions can be defined with SECURITY DEFINER or SECURITY INVOKER. The chosen option determines which role is used when the function executes.

Syntax

A CREATE FUNCTION statement may include:

CREATE FUNCTION schema_name.func_name(...)
RETURNS return_type
LANGUAGE plpgsql
SECURITY DEFINER   -- or SECURITY INVOKER (default)
SET search_path = 'public';

Setting search_path inside the function overrides the caller’s path.

Role Concepts: session_user vs current_user

session_user

: the role used to log in or the role set by SET SESSION AUTHORIZATION. current_user: the role active after SET ROLE or the role defined by a security‑definer function.

Source reference:

src/backend/utils/init/miscinit.c

Example: Test Function

The following function is created by the superuser postgres with SECURITY DEFINER and an explicit search_path:

CREATE OR REPLACE FUNCTION public.f1()
RETURNS void
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = 'public'
AS $$
BEGIN
    RAISE NOTICE 'search_path=%', current_setting('search_path');
    RAISE NOTICE 'current_role=%', current_user;
END;
$$;

When a regular user digoal calls public.f1(), the notices show: search_path = public (instead of the default "$user",public) current_role = postgres (the function owner)

Changing the definition to SECURITY INVOKER makes the same call report current_role = digoal.

Security Risks of SECURITY DEFINER

If a security‑definer function accesses objects without schema qualification, a non‑privileged user can manipulate the search_path or create objects in a schema that appears earlier in the path (including temporary schemas). This can bypass intended checks and lead to privilege escalation.

Mitigation Strategies

Always qualify object names with their schema (e.g., public.my_table).

Explicitly set a safe search_path inside the function, such as SET search_path = 'public', to prevent user‑controlled schemas from being searched.

Optionally, revoke CREATE privileges on schemas that appear before the safe schema.

Applying these measures causes the exploit attempts to fail, as demonstrated by the test runs.

References

PostgreSQL Documentation – CREATE FUNCTION:

http://www.postgresql.org/docs/9.5/static/sql-createfunction.html

Source code reference:

src/backend/utils/init/miscinit.c
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

PostgreSQLprivilege escalationDatabase RolesFunction SecuritySecurity Definer
dbaplus Community
Written by

dbaplus Community

Enterprise-level professional community for Database, BigData, and AIOps. Daily original articles, weekly online tech talks, monthly offline salons, and quarterly XCOPS&DAMS conferences—delivered by industry experts.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.