Permission elevation by pg_amcheck operator overloading via search_path possible?

First seen: 2026-05-22 12:39:33+00:00 · Messages: 1 · Participants: 1

Latest Update

2026-05-25 · claude-opus-4-6

Permission Elevation via pg_amcheck Operator Overloading Through search_path Manipulation

Core Problem

This thread raises a security vulnerability in pg_amcheck — PostgreSQL's built-in tool for verifying the structural integrity of indexes (based on the amcheck extension). The issue is a privilege escalation attack vector exploiting the interaction between search_path resolution and operator overloading.

The Attack Vector

pg_amcheck is a client-side utility that connects to a database and executes SQL queries to verify index integrity. Critically, it does not explicitly set search_path before running its queries. While the utility does schema-qualify table references (e.g., pg_catalog.pg_extension), it does not schema-qualify operators used in those queries.

The specific vulnerability chain:

  1. Precondition: The database-level search_path is configured to include a user-writable schema before pg_catalog (e.g., search_path = 'myschema, pg_catalog').

  2. Attack setup: A lower-privileged user creates a malicious operator = in myschema that matches the signature used in pg_amcheck's queries (e.g., name = name), backed by a function that performs privilege escalation (ALTER USER attacker WITH SUPERUSER) before returning the correct result.

  3. Trigger: When a superuser (or any highly-privileged role) runs pg_amcheck, the SQL queries it issues resolve the = operator through the search_path. Since myschema appears before pg_catalog, the malicious operator is found first and executed with the privileges of the connecting role.

  4. Result: The attacker gains superuser privileges.

Why This Matters Architecturally

This is an instance of a well-known class of PostgreSQL security issues: search_path-based privilege escalation in administrative tools. PostgreSQL has historically addressed similar issues in:

The fundamental architectural tension is:

The Fix Pattern

The standard mitigation for this class of vulnerability in PostgreSQL tools is straightforward:

  1. Set search_path to a safe value at the start of the session: SET search_path = pg_catalog or SET search_path = ''
  2. Alternatively, use the OPERATOR() syntax to schema-qualify operators: $1 OPERATOR(pg_catalog.=) $2

For pg_amcheck specifically, the fix would involve issuing SET search_path = 'pg_catalog' (or equivalent) immediately after connecting, before running any diagnostic queries. This is exactly what pg_dump does.

Severity Assessment

The severity depends on prerequisites:

While these preconditions are not universal, they are plausible in multi-tenant or shared environments (notably, the reporter is from Supabase, a hosted PostgreSQL platform where this exact configuration pattern is common).

Relationship to Broader Security Model

This vulnerability exists because pg_amcheck is a client-side tool that trusts the server's search_path configuration. Unlike server-side functions (which can be declared with SET search_path = pg_catalog or SECURITY DEFINER with controlled paths), client tools must proactively protect themselves. PostgreSQL's security model places the burden on tool authors to issue the appropriate SET commands, which is an easy step to overlook — particularly for a tool like pg_amcheck that schema-qualifies its table references but not its operators.