Re: BUG #19523: psql tab-completion shadows pg_db_role_setting
Hi,
Reproduced on current master. The tab-completion query for
"ALTER DATABASE ... RESET" (Query_for_list_of_database_vars) references
pg_db_role_setting and pg_database without a pg_catalog qualification, so a
same-named table earlier in search_path shadows the catalog:
CREATE SCHEMA attacker;
CREATE TABLE attacker.pg_db_role_setting (setdatabase oid, setrole
oid, setconfig text[]);
INSERT INTO attacker.pg_db_role_setting
SELECT oid, 0, ARRAY['evil_var=x'] FROM pg_database WHERE
datname = 'postgres';
SET search_path = attacker, pg_catalog;
-- "ALTER DATABASE postgres RESET <TAB>" then offers evil_var
The attached patch qualifies both catalogs with pg_catalog, matching the
qualification already used for unnest()/split_part() in the same query and for
the catalogs in the analogous subscription-variable completion query.
No test is included -- tab-completion query internals aren't covered by the
TAP suite, and this follows the earlier qualification fixes in the same area.
Affects v18 and master (the query was added in v18).
Regards,
Vismay Tiwari
Attachments:
v1-0001-psql-schema-qualify-catalog-references-in-a-tab-c.patchapplication/octet-stream; name=v1-0001-psql-schema-qualify-catalog-references-in-a-tab-c.patchDownload+2-3
Hi! You seem to create two threads on the issue, so I don't quite
understand where to respond. anyway:
On Thu, 9 Jul 2026, 15:14 Vismay Tiwari, <vismay.t@gmail.com> wrote:
Hi,
Reproduced on current master. The tab-completion query for
"ALTER DATABASE ... RESET" (Query_for_list_of_database_vars) references
pg_db_role_setting and pg_database without a pg_catalog qualification, so a
same-named table earlier in search_path shadows the catalog:CREATE SCHEMA attacker;
CREATE TABLE attacker.pg_db_role_setting (setdatabase oid, setrole
oid, setconfig text[]);
INSERT INTO attacker.pg_db_role_setting
SELECT oid, 0, ARRAY['evil_var=x'] FROM pg_database WHERE
datname = 'postgres';
SET search_path = attacker, pg_catalog;
-- "ALTER DATABASE postgres RESET <TAB>" then offers evil_var
Preventing this makes sense in case somebody accidentally misconfigured
their server. Which is not very probable for a table with `
pg_db_role_setting` name.
Also note that this is not a vulnerability: from
https://www.postgresql.org/docs/current/app-psql.html says:
If untrusted users have access to a database that has not adopted a secure
schema usage pattern, begin your session by removing publicly-writable
schemas from search_path.
Anyway +1 on fixing
Hi Kirill,
Thanks, and sorry for the two threads — the second was an accidental
resend that didn't thread properly on my end , so let's keep it here.
You're right that it's not a vulnerability, and the "attacker" framing
was overblown — the docs are clear that removing publicly-writable
schemas from search_path is the real safeguard. The intent is just
consistency and robustness: the same query already qualifies
unnest()/split_part() with pg_catalog, and the analogous
subscription-variable completion query qualifies its catalogs, so this
only brings pg_db_role_setting/pg_database in line. As a side benefit
it avoids a surprising tab-completion result for anyone who happens to
have a same-named table earlier in search_path, misconfigured or not.
Thanks for the +1.
Regards,
Vismay
Show quoted text
On Fri, Jul 10, 2026 at 10:19 AM Kirill Reshke <reshkekirill@gmail.com> wrote:
Hi! You seem to create two threads on the issue, so I don't quite understand where to respond. anyway:
On Thu, 9 Jul 2026, 15:14 Vismay Tiwari, <vismay.t@gmail.com> wrote:
Hi,
Reproduced on current master. The tab-completion query for
"ALTER DATABASE ... RESET" (Query_for_list_of_database_vars) references
pg_db_role_setting and pg_database without a pg_catalog qualification, so a
same-named table earlier in search_path shadows the catalog:CREATE SCHEMA attacker;
CREATE TABLE attacker.pg_db_role_setting (setdatabase oid, setrole
oid, setconfig text[]);
INSERT INTO attacker.pg_db_role_setting
SELECT oid, 0, ARRAY['evil_var=x'] FROM pg_database WHERE
datname = 'postgres';
SET search_path = attacker, pg_catalog;
-- "ALTER DATABASE postgres RESET <TAB>" then offers evil_varPreventing this makes sense in case somebody accidentally misconfigured their server. Which is not very probable for a table with `pg_db_role_setting` name.
Also note that this is not a vulnerability: from https://www.postgresql.org/docs/current/app-psql.html says:If untrusted users have access to a database that has not adopted a secure
schema usage pattern, begin your session by removing publicly-writable
schemas from search_path.Anyway +1 on fixing