← THE INDEX  ·  WRITEUP

aiven_gatekeeper Bypass via Implicitly Castable Argument Types

Aiven's PostgreSQL security agent blocks shadow functions with identical signatures but misses those with different, implicitly castable argument types, defeating its own pghostile-class protection.

Summary

aiven_gatekeeper is a PostgreSQL shared library Aiven uses to block the class of privilege escalation attack documented by their own pghostile tool: unprivileged users creating shadow functions in the public schema that override pg_catalog system functions. The gatekeeper correctly blocks shadow functions with identical argument signatures, but it does not block shadows with different argument types that are implicitly castable from the caller's argument type. PostgreSQL function resolution prefers an exact-match on the argument type, so public.sha256(text) wins over pg_catalog.sha256(bytea) when the argument is a text literal, even though the gatekeeper treats them as different functions.

Impact

The bypass allows any authenticated avnadmin user to create shadow functions that intercept calls to the approximately 907 exploitable pg_catalog functions identified by pghostile. This is the enabler for the companion autovacuum code execution report, where the shadow function runs in the autovacuum superuser context. More broadly, the gatekeeper was specifically designed to prevent this attack class; the bypass means the protection is incomplete and a determined attacker can plant arbitrary code in a superuser execution path.

Root cause

The gatekeeper intercepts CREATE FUNCTION and checks whether the new function's name and argument types exactly match a pg_catalog function. It does not check whether the new function's name matches a pg_catalog function AND the argument types are implicitly castable between the two. PostgreSQL's function resolution algorithm, documented in section 10.3 of the manual, prefers exact type matches. A text literal passed to sha256() is an exact match for public.sha256(text) and only a cast-match for pg_catalog.sha256(bytea), so the shadow wins even though the gatekeeper believed it was harmless.

Every other function call in aiven_extras SECURITY DEFINER bodies is schema-qualified (pg_catalog.format, pg_catalog.array_length, etc.), which would prevent shadowing in those specific calls. The gatekeeper bypass matters most for code paths evaluated outside the SECDEF context, such as expression indexes evaluated by autovacuum.

Proof of concept

The following creates a shadow function with a different argument type and confirms it is called instead of the pg_catalog version.

Disclosure and fix

Reported to Aiven through their bug bounty program alongside the autovacuum code execution chain. Aiven triaged this as P2 (High). The recommended fix is to extend aiven_gatekeeper to block function creation in public and other user-accessible schemas when the function name matches any pg_catalog function, regardless of whether the argument types are identical or merely implicitly castable. A conservative implementation would block any function whose name matches a pg_catalog function AND whose argument types are implicitly castable to those of any pg_catalog overload with the same name.