public inbox for pgsql-bugs@postgresql.org  
help / color / mirror / Atom feed
From: PG Bug reporting form <noreply@postgresql.org>
To: pgsql-bugs@lists.postgresql.org
Cc: zengman@halodbtech.com
Subject: BUG #19478: `dblink_close` can be used for injection.
Date: Fri, 15 May 2026 01:29:54 +0000
Message-ID: <19478-37289e8b0d1a1299@postgresql.org> (raw)

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







reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: pgsql-bugs@postgresql.org
  Cc: noreply@postgresql.org, pgsql-bugs@lists.postgresql.org, zengman@halodbtech.com
  Subject: Re: BUG #19478: `dblink_close` can be used for injection.
  In-Reply-To: <19478-37289e8b0d1a1299@postgresql.org>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox