Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1waDQS-001bzq-2M for pgsql-bugs@arkaria.postgresql.org; Thu, 18 Jun 2026 14:09:01 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1waDQR-00Bjf8-0r for pgsql-bugs@arkaria.postgresql.org; Thu, 18 Jun 2026 14:08:59 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wa6qC-00AGzF-1B for pgsql-bugs@lists.postgresql.org; Thu, 18 Jun 2026 07:07:08 +0000 Received: from mahout.postgresql.org ([2001:4800:3e1:1::227]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1wa6qB-00000000vvt-04xx for pgsql-bugs@lists.postgresql.org; Thu, 18 Jun 2026 07:07:07 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=postgresql.org; s=20171124; h=Message-ID:Date:Reply-To:Cc:From:To:Subject: Content-Transfer-Encoding:MIME-Version:Content-Type:Sender:Content-ID: Content-Description:In-Reply-To:References; bh=wjAR5QDC1W6JeAchQtEnkJrcfJ+XkY29bzLoQofnQLk=; b=4NtBQ6D1fEl5Eynyxkp4Sy6aPX l1lIUp0HMLpGeAlbsv2rzZ2Bo9wR2YGMejlIwSnjASSv+JSX2tWwXH9fLts1ZDlcGQYsRGdyCH/wB EY+oj8AtGUhm0W+gAukQq2oJ46hnBe+6UUyEP8ygjVhGzk/n5iCGwe2G1mUJ97wyw1RxKajfsbq/W c4Pcv1vTnY9pSMNuwsednVjXKFauAUv7rICTNGiD8rNtLXUSHxf3a1yn6lv7+GJj3Hj08OmwITBwg GYfSPN+f83Yxz/gEISowPRtepCIWwgTeKu7tigW1H4mu3jMziNIRLjafnSRaS/E9oUElnqvXWzLHn v3e2ZHxA==; Received: from wrigleys.postgresql.org ([2a02:16a8:dc51::60]) by mahout.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wa6q8-002q89-01 for pgsql-bugs@lists.postgresql.org; Thu, 18 Jun 2026 07:07:06 +0000 Received: from localhost ([127.0.0.1] helo=wrigleys.postgresql.org) by wrigleys.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wa6q6-006SOA-35 for pgsql-bugs@lists.postgresql.org; Thu, 18 Jun 2026 07:07:03 +0000 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Subject: BUG #19523: psql tab-completion shadows pg_db_role_setting To: pgsql-bugs@lists.postgresql.org From: PG Bug reporting form Cc: digoal@126.com Reply-To: digoal@126.com, pgsql-bugs@lists.postgresql.org Date: Thu, 18 Jun 2026 07:06:44 +0000 Message-ID: <19523-424457118202f570@postgresql.org> X-Auto-Response-Suppress: All Auto-Submitted: auto-generated List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk The following bug has been logged on the website: Bug reference: 19523 Logged by: Zhou Digoal Email address: digoal@126.com PostgreSQL version: 19beta1 Operating system: macOS Description: =20 # =F0=9F=90=9B [BUG] psql tab-completion shadows pg_db_role_setting ## Environment | Item | Value | | --- | --- | | OS | macOS 15.7.7 (build 24G720) | | Kernel | Darwin 24.6.0 | | Compiler | Apple clang version 17.0.0 (clang-1700.6.4.2) | | PG version | 19beta1 (`pg_config --version`) | | Source branch | `master` | | Source commit | `850b9218c8e4aa7a56f4ec34a542d4a37f9e07eb` | | `git describe` | `850b921` | | Build flags | `--enable-debug --enable-cassert --enable-debug-symbols` | | Configure | `$PGBIN/pg_config --configure` | --- ## Summary The query that psql tab-completion runs to list database-scoped GUC names (Query_for_list_of_database_vars in src/bin/psql/tab-complete.c, duplicated in src/bin/psql/tab-complete.in.c) references the system catalog table pg_db_role_setting without the pg_catalog. schema qualifier. A user with CREATE privilege on any schema earlier in search_path than pg_catalog can therefore shadow the catalog table and influence tab-completion suggestions for ALTER DATABASE SET. --- ## Commit under test `850b9218c8e4aa7a56f4ec34a542d4a37f9e07eb` on branch `master`. The full source HEAD at report time is `850b9218c8e4aa7a56f4ec34a542d4a37f9e07eb` (`git describe` =E2=86=92 `850b921`). --- ## Reproduction Repro file: `/tmp/repro_pg_db_role_setting.sql` ```sql 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['custom_var=3Dvalue', 'session_replication_role=3Drepl= ica'] FROM pg_database WHERE datname =3D 'postgres'; SET search_path =3D attacker, pg_catalog; SELECT conf FROM ( SELECT setdatabase, pg_catalog.split_part(pg_catalog.unnest(setconfig),'=3D',1) conf FROM pg_db_role_setting ) s, pg_database d WHERE s.setdatabase =3D d.oid AND conf LIKE 'c%' AND d.datname LIKE 'p%'; RESET search_path; DROP SCHEMA attacker CASCADE; ``` ### Actual output ``` Returned one row 'custom_var' that was read from attacker.pg_db_role_setting rather than from the system catalog (which is empty for this database). ``` ### Server log (last lines) ``` CREATE SCHEMA attacker; CREATE SCHEMA CREATE TABLE attacker.pg_db_role_setting ( setdatabase oid, setrole oid, setconfig text[] ); CREATE TABLE INSERT INTO attacker.pg_db_role_setting SELECT oid, 0, ARRAY['custom_var=3Dvalue', 'session_replication_role=3Drepl= ica'] FROM pg_database WHERE datname =3D 'postgres'; INSERT 0 1 SET search_path =3D attacker, pg_catalog; SET SELECT conf FROM ( SELECT setdatabase, pg_catalog.split_part(pg_catalog.unnest(setconfig),'=3D',1) conf FROM pg_db_role_setting ) s, pg_database d WHERE s.setdatabase =3D d.oid AND conf LIKE 'c%' AND d.datname LIKE 'p%'; conf ------------ custom_var (1 row) RESET search_path; RESET DROP SCHEMA attacker CASCADE; psql:/tmp/repro_pg_db_role_setting.sql:48: NOTICE: drop cascades to table attacker.pg_db_role_setting DROP SCHEMA ``` ### Expected output ``` Zero rows; the query should resolve pg_db_role_setting to the system catalog table regardless of search_path. ``` --- ## Why is this a bug? Commit bf5206f (psql: Add some missing schema qualifications in describe.c) fixed the same class of bug for describe.c but missed tab-complete.c and tab-complete.in.c. A user who can create a table named pg_db_role_setting in a schema that appears before pg_catalog in search_path can have psql issue its tab-completion query against the shadow table instead of the real catalog, returning attacker- controlled GUC names. This violates the documented psql behavior of suggesting actual database-level GUC settings. --- ## Suggested fix Qualify the reference in src/bin/psql/tab-complete.in.c (line 1043) and the generated src/bin/psql/tab-complete.c (line 1064) by changing FROM pg_db_role_setting to FROM pg_catalog.pg_db_role_setting, then regenerate tab-complete.c on rebuild. --- ## Severity **medium** =E2=80=94 see Environment block.