public inbox for pgsql-bugs@postgresql.org
help / color / mirror / Atom feedBUG #19478: `dblink_close` can be used for injection.
5+ messages / 4 participants
[nested] [flat]
* BUG #19478: `dblink_close` can be used for injection.
@ 2026-05-15 01:29 PG Bug reporting form <noreply@postgresql.org>
0 siblings, 1 reply; 5+ messages in thread
From: PG Bug reporting form @ 2026-05-15 01:29 UTC (permalink / raw)
To: pgsql-bugs@lists.postgresql.org; +Cc: zengman@halodbtech.com
The following bug has been logged on the website:
Bug reference: 19478
Logged by: Man Zeng
Email address: zengman@halodbtech.com
PostgreSQL version: 18.4
Operating system: 24.04.1-Ubuntu
Description:
Hi all,
I think we can impose stricter restrictions on the parameters of
`dblink_close`.
For example, when calling `dblink_close`, certain operations can be achieved
through SQL concatenation,
which I believe is unexpected behavior.
```sql
postgres@zxm-VMware-Virtual-Platform:~/Z-Xiao-M$ psql
psql (19devel)
Type "help" for help.
postgres=# \c test
You are now connected to database "test" as user "postgres".
test=# CREATE EXTENSION IF NOT EXISTS dblink;
CREATE EXTENSION
test=# SELECT dblink_connect('c', 'dbname=' || current_database());
dblink_connect
----------------
OK
(1 row)
test=# SELECT dblink_open('c', 'cur', 'SELECT 1');
dblink_open
-------------
OK
(1 row)
test=# -- CLOSE: CREATE TABLE
test=# SELECT dblink_close('c', 'cur; CREATE TABLE hacked(id int); --');
dblink_close
--------------
OK
(1 row)
test=# \d+ hacked
Table "public.hacked"
Column | Type | Collation | Nullable | Default | Storage | Compression |
Stats target | Description
--------+---------+-----------+----------+---------+---------+-------------+--------------+-------------
id | integer | | | | plain | |
|
Access method: heap
test=# SELECT dblink_disconnect('c');
dblink_disconnect
-------------------
OK
(1 row)
test=# SELECT dblink_connect('c', 'dbname=' || current_database());
dblink_connect
----------------
OK
(1 row)
test=# SELECT dblink_open('c', 'cur', 'SELECT 1');
dblink_open
-------------
OK
(1 row)
test=# -- CLOSE: DROP TABLE
test=# SELECT dblink_close('c', 'cur; DROP TABLE hacked; --');
dblink_close
--------------
OK
(1 row)
test=# \d+ hacked
Did not find any relation named "hacked".
test=#
```
This is my SQL for reproducing the problem.
```sql
CREATE EXTENSION IF NOT EXISTS dblink;
SELECT dblink_connect('c', 'dbname=' || current_database());
SELECT dblink_open('c', 'cur', 'SELECT 1');
-- CLOSE: CREATE TABLE
SELECT dblink_close('c', 'cur; CREATE TABLE hacked(id int); --');
SELECT dblink_disconnect('c');
\d+ hacked
SELECT dblink_connect('c', 'dbname=' || current_database());
SELECT dblink_open('c', 'cur', 'SELECT 1');
-- CLOSE: DROP TABLE
SELECT dblink_close('c', 'cur; DROP TABLE hacked; --');
\d+ hacked
SELECT dblink_disconnect('c');
```
The solution to this problem is also very simple.
```
postgres@zxm-VMware-Virtual-Platform:~/code/postgres/contrib$ git diff
diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 9798cb535bc..0a9334aa160 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -543,7 +543,7 @@ dblink_close(PG_FUNCTION_ARGS)
conn = rconn->conn;
- appendStringInfo(&buf, "CLOSE %s", curname);
+ appendStringInfo(&buf, "CLOSE %s", quote_ident_cstr(curname));
/* close the cursor */
res = libpqsrv_exec(conn, buf.data, dblink_we_get_result);
```
This is the feedback from the security team.
```
Thanks for your report. We consider dblink_close() to be caller-trusted,
and thus this is not considered a security vulnerability. Feel free to
resubmit to pgsql-bugs@lists.postgresql.org.
```
Any thought?
--
regards,
Man Zeng
^ permalink raw reply [nested|flat] 5+ messages in thread
* Re: BUG #19478: `dblink_close` can be used for injection.
@ 2026-05-16 01:24 Japin Li <japinli@hotmail.com>
parent: PG Bug reporting form <noreply@postgresql.org>
0 siblings, 1 reply; 5+ messages in thread
From: Japin Li @ 2026-05-16 01:24 UTC (permalink / raw)
To: pgsql-bugs@lists.postgresql.org; +Cc: zengman@halodbtech.com
On Fri, 15 May 2026 at 01:29, PG Bug reporting form <noreply@postgresql.org> wrote:
> The following bug has been logged on the website:
>
> Bug reference: 19478
> Logged by: Man Zeng
> Email address: zengman@halodbtech.com
> PostgreSQL version: 18.4
> Operating system: 24.04.1-Ubuntu
> Description:
>
> Hi all,
>
> I think we can impose stricter restrictions on the parameters of
> `dblink_close`.
> For example, when calling `dblink_close`, certain operations can be achieved
> through SQL concatenation,
> which I believe is unexpected behavior.
>
> ```sql
> postgres@zxm-VMware-Virtual-Platform:~/Z-Xiao-M$ psql
> psql (19devel)
> Type "help" for help.
>
> postgres=# \c test
> You are now connected to database "test" as user "postgres".
> test=# CREATE EXTENSION IF NOT EXISTS dblink;
> CREATE EXTENSION
> test=# SELECT dblink_connect('c', 'dbname=' || current_database());
> dblink_connect
> ----------------
> OK
> (1 row)
>
> test=# SELECT dblink_open('c', 'cur', 'SELECT 1');
> dblink_open
> -------------
> OK
> (1 row)
>
> test=# -- CLOSE: CREATE TABLE
> test=# SELECT dblink_close('c', 'cur; CREATE TABLE hacked(id int); --');
> dblink_close
> --------------
> OK
> (1 row)
>
> test=# \d+ hacked
> Table "public.hacked"
> Column | Type | Collation | Nullable | Default | Storage | Compression |
> Stats target | Description
> --------+---------+-----------+----------+---------+---------+-------------+--------------+-------------
> id | integer | | | | plain | |
> |
> Access method: heap
>
> test=# SELECT dblink_disconnect('c');
> dblink_disconnect
> -------------------
> OK
> (1 row)
>
> test=# SELECT dblink_connect('c', 'dbname=' || current_database());
> dblink_connect
> ----------------
> OK
> (1 row)
>
> test=# SELECT dblink_open('c', 'cur', 'SELECT 1');
> dblink_open
> -------------
> OK
> (1 row)
>
> test=# -- CLOSE: DROP TABLE
> test=# SELECT dblink_close('c', 'cur; DROP TABLE hacked; --');
> dblink_close
> --------------
> OK
> (1 row)
>
> test=# \d+ hacked
> Did not find any relation named "hacked".
> test=#
> ```
>
> This is my SQL for reproducing the problem.
> ```sql
> CREATE EXTENSION IF NOT EXISTS dblink;
>
> SELECT dblink_connect('c', 'dbname=' || current_database());
> SELECT dblink_open('c', 'cur', 'SELECT 1');
>
> -- CLOSE: CREATE TABLE
> SELECT dblink_close('c', 'cur; CREATE TABLE hacked(id int); --');
>
> SELECT dblink_disconnect('c');
> \d+ hacked
>
> SELECT dblink_connect('c', 'dbname=' || current_database());
> SELECT dblink_open('c', 'cur', 'SELECT 1');
>
> -- CLOSE: DROP TABLE
> SELECT dblink_close('c', 'cur; DROP TABLE hacked; --');
>
> \d+ hacked
> SELECT dblink_disconnect('c');
> ```
>
> The solution to this problem is also very simple.
> ```
> postgres@zxm-VMware-Virtual-Platform:~/code/postgres/contrib$ git diff
> diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
> index 9798cb535bc..0a9334aa160 100644
> --- a/contrib/dblink/dblink.c
> +++ b/contrib/dblink/dblink.c
> @@ -543,7 +543,7 @@ dblink_close(PG_FUNCTION_ARGS)
>
> conn = rconn->conn;
>
> - appendStringInfo(&buf, "CLOSE %s", curname);
> + appendStringInfo(&buf, "CLOSE %s", quote_ident_cstr(curname));
>
> /* close the cursor */
> res = libpqsrv_exec(conn, buf.data, dblink_we_get_result);
> ```
>
> This is the feedback from the security team.
> ```
> Thanks for your report. We consider dblink_close() to be caller-trusted,
> and thus this is not considered a security vulnerability. Feel free to
> resubmit to pgsql-bugs@lists.postgresql.org.
> ```
>
> Any thought?
According to the documentation [1], it should be a cursor name. Wrapping it
in quotes can prevent attacks like SQL injection. I think your modification
is correct, and we should add test cases for it.
[1] https://www.postgresql.org/docs/current/contrib-dblink-close.html
> --
> regards,
> Man Zeng
--
Regards,
Japin Li
ChengDu WenWu Information Technology Co., Ltd.
^ permalink raw reply [nested|flat] 5+ messages in thread
* Re: BUG #19478: `dblink_close` can be used for injection.
@ 2026-05-16 04:06 Kirill Reshke <reshkekirill@gmail.com>
parent: Japin Li <japinli@hotmail.com>
0 siblings, 1 reply; 5+ messages in thread
From: Kirill Reshke @ 2026-05-16 04:06 UTC (permalink / raw)
To: Japin Li <japinli@hotmail.com>; +Cc: PostgreSQL mailing lists <pgsql-bugs@lists.postgresql.org>; zengman <zengman@halodbtech.com>
On Sat, 16 May 2026, 06:24 Japin Li, <japinli@hotmail.com> wrote:
> On Fri, 15 May 2026 at 01:29, PG Bug reporting form <
> noreply@postgresql.org> wrote:
> > The following bug has been logged on the website:
> >
> > Bug reference: 19478
> > Logged by: Man Zeng
> > Email address: zengman@halodbtech.com
> > PostgreSQL version: 18.4
> > Operating system: 24.04.1-Ubuntu
> > Description:
> >
> > Hi all,
> >
> > I think we can impose stricter restrictions on the parameters of
> > `dblink_close`.
> > For example, when calling `dblink_close`, certain operations can be
> achieved
> > through SQL concatenation,
> > which I believe is unexpected behavior.
> >
> > ```sql
> > postgres@zxm-VMware-Virtual-Platform:~/Z-Xiao-M$ psql
> > psql (19devel)
> > Type "help" for help.
> >
> > postgres=# \c test
> > You are now connected to database "test" as user "postgres".
> > test=# CREATE EXTENSION IF NOT EXISTS dblink;
> > CREATE EXTENSION
> > test=# SELECT dblink_connect('c', 'dbname=' || current_database());
> > dblink_connect
> > ----------------
> > OK
> > (1 row)
> >
> > test=# SELECT dblink_open('c', 'cur', 'SELECT 1');
> > dblink_open
> > -------------
> > OK
> > (1 row)
> >
> > test=# -- CLOSE: CREATE TABLE
> > test=# SELECT dblink_close('c', 'cur; CREATE TABLE hacked(id int); --');
> > dblink_close
> > --------------
> > OK
> > (1 row)
> >
> > test=# \d+ hacked
> > Table "public.hacked"
> > Column | Type | Collation | Nullable | Default | Storage |
> Compression |
> > Stats target | Description
> >
> --------+---------+-----------+----------+---------+---------+-------------+--------------+-------------
> > id | integer | | | | plain |
> |
> > |
> > Access method: heap
> >
> > test=# SELECT dblink_disconnect('c');
> > dblink_disconnect
> > -------------------
> > OK
> > (1 row)
> >
> > test=# SELECT dblink_connect('c', 'dbname=' || current_database());
> > dblink_connect
> > ----------------
> > OK
> > (1 row)
> >
> > test=# SELECT dblink_open('c', 'cur', 'SELECT 1');
> > dblink_open
> > -------------
> > OK
> > (1 row)
> >
> > test=# -- CLOSE: DROP TABLE
> > test=# SELECT dblink_close('c', 'cur; DROP TABLE hacked; --');
> > dblink_close
> > --------------
> > OK
> > (1 row)
> >
> > test=# \d+ hacked
> > Did not find any relation named "hacked".
> > test=#
> > ```
> >
> > This is my SQL for reproducing the problem.
> > ```sql
> > CREATE EXTENSION IF NOT EXISTS dblink;
> >
> > SELECT dblink_connect('c', 'dbname=' || current_database());
> > SELECT dblink_open('c', 'cur', 'SELECT 1');
> >
> > -- CLOSE: CREATE TABLE
> > SELECT dblink_close('c', 'cur; CREATE TABLE hacked(id int); --');
> >
> > SELECT dblink_disconnect('c');
> > \d+ hacked
> >
> > SELECT dblink_connect('c', 'dbname=' || current_database());
> > SELECT dblink_open('c', 'cur', 'SELECT 1');
> >
> > -- CLOSE: DROP TABLE
> > SELECT dblink_close('c', 'cur; DROP TABLE hacked; --');
> >
> > \d+ hacked
> > SELECT dblink_disconnect('c');
> > ```
> >
> > The solution to this problem is also very simple.
> > ```
> > postgres@zxm-VMware-Virtual-Platform:~/code/postgres/contrib$ git diff
> > diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
> > index 9798cb535bc..0a9334aa160 100644
> > --- a/contrib/dblink/dblink.c
> > +++ b/contrib/dblink/dblink.c
> > @@ -543,7 +543,7 @@ dblink_close(PG_FUNCTION_ARGS)
> >
> > conn = rconn->conn;
> >
> > - appendStringInfo(&buf, "CLOSE %s", curname);
> > + appendStringInfo(&buf, "CLOSE %s", quote_ident_cstr(curname));
> >
> > /* close the cursor */
> > res = libpqsrv_exec(conn, buf.data, dblink_we_get_result);
> > ```
> >
> > This is the feedback from the security team.
> > ```
> > Thanks for your report. We consider dblink_close() to be caller-trusted,
> > and thus this is not considered a security vulnerability. Feel free to
> > resubmit to pgsql-bugs@lists.postgresql.org.
> > ```
> >
> > Any thought?
>
> According to the documentation [1], it should be a cursor name. Wrapping
> it
> in quotes can prevent attacks like SQL injection. I think your
> modification
> is correct, and we should add test cases for it.
>
> [1] https://www.postgresql.org/docs/current/contrib-dblink-close.html
>
> > --
> > regards,
> > Man Zeng
>
> --
> Regards,
> Japin Li
> ChengDu WenWu Information Technology Co., Ltd.
>
Well, is there any actual injection? I mean, if user can execute
dblink_close, then user can do an SQL with dblink_open and simply do a SQL?
Unless wierd case when we only granted with close function, I guess
^ permalink raw reply [nested|flat] 5+ messages in thread
* Re: BUG #19478: `dblink_close` can be used for injection.
@ 2026-05-16 04:28 David G. Johnston <david.g.johnston@gmail.com>
parent: Kirill Reshke <reshkekirill@gmail.com>
0 siblings, 1 reply; 5+ messages in thread
From: David G. Johnston @ 2026-05-16 04:28 UTC (permalink / raw)
To: Kirill Reshke <reshkekirill@gmail.com>; +Cc: Japin Li <japinli@hotmail.com>; PostgreSQL mailing lists <pgsql-bugs@lists.postgresql.org>; zengman <zengman@halodbtech.com>
On Friday, May 15, 2026, Kirill Reshke <reshkekirill@gmail.com> wrote:
>
>
> On Sat, 16 May 2026, 06:24 Japin Li, <japinli@hotmail.com> wrote:
>
>> On Fri, 15 May 2026 at 01:29, PG Bug reporting form <
>> noreply@postgresql.org> wrote:
>> > The following bug has been logged on the website:
>> >
>> > Bug reference: 19478
>> > Logged by: Man Zeng
>> > Email address: zengman@halodbtech.com
>> > PostgreSQL version: 18.4
>> > Operating system: 24.04.1-Ubuntu
>> > Description:
>> >
>> >
>> >
>> > - appendStringInfo(&buf, "CLOSE %s", curname);
>> > + appendStringInfo(&buf, "CLOSE %s", quote_ident_cstr(curname));
>> >
>>
>>
>> According to the documentation [1], it should be a cursor name. Wrapping
>> it
>> in quotes can prevent attacks like SQL injection. I think your
>> modification
>> is correct, and we should add test cases for it.
>>
>> [1] https://www.postgresql.org/docs/current/contrib-dblink-close.html
>>
>
> Well, is there any actual injection? I mean, if user can execute
>> dblink_close, then user can do an SQL with dblink_open and simply do a SQL?
>> Unless wierd case when we only granted with close function, I guess
>>
>
Switching to quote_ident means we no longer lowercase an unquoted input.
Is this improvement in api design worth the potential breakage? If so,
make sure we at least change the dblink_open (and fetch…) code similarly.
I’m disinclined to change this unless it’s shown the only possible use of
the identifier is within the dblink function arguments where can change all
uses to quote_identifier. Even then, inconsistent capitalization still
might exist.
David J.
^ permalink raw reply [nested|flat] 5+ messages in thread
* Re: BUG #19478: `dblink_close` can be used for injection.
@ 2026-05-18 03:10 Japin Li <japinli@hotmail.com>
parent: David G. Johnston <david.g.johnston@gmail.com>
0 siblings, 0 replies; 5+ messages in thread
From: Japin Li @ 2026-05-18 03:10 UTC (permalink / raw)
To: David G. Johnston <david.g.johnston@gmail.com>; +Cc: Kirill Reshke <reshkekirill@gmail.com>; PostgreSQL mailing lists <pgsql-bugs@lists.postgresql.org>; zengman <zengman@halodbtech.com>
On Fri, 15 May 2026 at 21:28, "David G. Johnston" <david.g.johnston@gmail.com> wrote:
> On Friday, May 15, 2026, Kirill Reshke <reshkekirill@gmail.com> wrote:
>
> On Sat, 16 May 2026, 06:24 Japin Li, <japinli@hotmail.com> wrote:
>
> On Fri, 15 May 2026 at 01:29, PG Bug reporting form <noreply@postgresql.org> wrote:
> > The following bug has been logged on the website:
> >
> > Bug reference: 19478
> > Logged by: Man Zeng
> > Email address: zengman@halodbtech.com
> > PostgreSQL version: 18.4
> > Operating system: 24.04.1-Ubuntu
> > Description:
> >
> >
> >
> > - appendStringInfo(&buf, "CLOSE %s", curname);
> > + appendStringInfo(&buf, "CLOSE %s", quote_ident_cstr(curname));
> >
>
> According to the documentation [1], it should be a cursor name. Wrapping it
> in quotes can prevent attacks like SQL injection. I think your modification
> is correct, and we should add test cases for it.
>
> [1] https://www.postgresql.org/docs/current/contrib-dblink-close.html
>
>
> Well, is there any actual injection? I mean, if user can execute dblink_close, then user can do an SQL with
> dblink_open and simply do a SQL? Unless wierd case when we only granted with close function, I guess
>
I think this is similar to SQL injection. However, no actual injection happened.
> Switching to quote_ident means we no longer lowercase an unquoted input. Is this improvement in api design worth the
> potential breakage? If so, make sure we at least change the dblink_open (and fetch…) code similarly.
>
> I’m disinclined to change this unless it’s shown the only possible use of the identifier is within the dblink function
> arguments where can change all uses to quote_identifier. Even then, inconsistent capitalization still might exist.
>
I don't think the current implementation is acceptable. Could we restrict the
cursor name to an identifier characters?
> David J.
--
Regards,
Japin Li
ChengDu WenWu Information Technology Co., Ltd.
^ permalink raw reply [nested|flat] 5+ messages in thread
end of thread, other threads:[~2026-05-18 03:10 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2026-05-15 01:29 BUG #19478: `dblink_close` can be used for injection. PG Bug reporting form <noreply@postgresql.org>
2026-05-16 01:24 ` Japin Li <japinli@hotmail.com>
2026-05-16 04:06 ` Kirill Reshke <reshkekirill@gmail.com>
2026-05-16 04:28 ` David G. Johnston <david.g.johnston@gmail.com>
2026-05-18 03:10 ` Japin Li <japinli@hotmail.com>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox