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:
-
Precondition: The database-level
search_pathis configured to include a user-writable schema beforepg_catalog(e.g.,search_path = 'myschema, pg_catalog'). -
Attack setup: A lower-privileged user creates a malicious operator
=inmyschemathat 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. -
Trigger: When a superuser (or any highly-privileged role) runs
pg_amcheck, the SQL queries it issues resolve the=operator through thesearch_path. Sincemyschemaappears beforepg_catalog, the malicious operator is found first and executed with the privileges of the connecting role. -
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:
pg_dump(which setssearch_pathto empty string since CVE fixes)pg_restorevacuumdb- Various
contribmodules that useSET search_pathin their function definitions
The fundamental architectural tension is:
- PostgreSQL's operator resolution depends on
search_path(operators are not typically schema-qualified in SQL text) - Client tools that execute SQL inherit the session's
search_pathunless they explicitly override it - Administrative tools often run with elevated privileges, making them attractive targets
The Fix Pattern
The standard mitigation for this class of vulnerability in PostgreSQL tools is straightforward:
- Set
search_pathto a safe value at the start of the session:SET search_path = pg_catalogorSET search_path = '' - 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:
- Requires a database with a non-default
search_paththat places a user-writable schema beforepg_catalog - Requires a privileged user to run
pg_amcheckagainst that database - The attacker needs
CREATEprivilege on the leading schema
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.