Possible command-injection or meta-command execution in `psql` input

From: PG Doc comments form <noreply(at)postgresql(dot)org>
To: pgsql-docs(at)lists(dot)postgresql(dot)org
Cc: y(dot)saburov(at)gmail(dot)com
Subject: Possible command-injection or meta-command execution in `psql` input
Date: 2026-09-26 08:27:10
Message-ID: 179041123000.1026192.10336293169834979882@wrigleys.postgresql.org
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-docs

The following documentation comment has been logged on the website:

Page: https://www.postgresql.org/docs/18/index.html
Description:

AI generated ))

## Summary

The following SQL statement contains an unquoted regular-expression-like
expression:

```sql
db=# WITH products (id, name, price, action) AS
(
VALUES
(1, 'apple', 100, '...')
, (2, 'banana', 200, '...')
, (3, 'orange', 150, '...')
, (4, 'potato', 80, '...')
, (5, 'tomato', 120, '...')
)
SELECT
p.id
, p.name
, p.price
, p.action
FROM products AS p
WHERE regexp_like(p.action, ((?<!-)\d+))
;
```

The observed output is:

```text
List of relations
Schema | Name | Type | Owner | Persistence | Access method |
Size | Description
--------+----------------+-------+----------+-------------+---------------+------------+-------------
public | inventory_item | table | postgres | permanent | heap | 16 kB |
public | mytab | table | postgres | permanent | heap | 16 kB |
public | on_hand | table | postgres | permanent | heap | 16 kB |
public | suppliers | table | postgres | permanent | heap | 8192 bytes
|
public | test_table | table | postgres | permanent | heap | 16 kB |
public | users | table | postgres | permanent | heap | 16 kB |
(6 rows)

db(#
```

The expected result of the SQL query would be either:

```text
ERROR: invalid regular expression: parentheses () not balanced
```

or a normal result set from the `SELECT`.

Instead, the output contains a relation listing followed by the continuation
prompt:

```text
db(#
```

## Security concern

The relation listing resembles the output of a `psql` meta-command such as:

```psql
\d
```

or:

```psql
\dt
```

The displayed output is not a normal result of the `SELECT` statement shown
above. The query does not select from the system catalog and does not
contain any statement that would produce a `List of relations` table.

This raises the following questions:

1. Why does the input produce `psql` meta-command output?
2. Was a `psql` backslash command such as `\d` or `\dt` executed during
processing?
3. Is the regular-expression text being interpreted as `psql` input or as
SQL text?
4. Can other `psql` meta-commands be injected or executed in the same
context?
5. Are the SQL parser, the `psql` client parser, and the regular-expression
parser processing the input in the expected order?
6. Are there any restrictions on which backslash commands can be executed?
7. Can this behavior expose database metadata or execute other client-side
commands?

The concern is not limited to the meaning of `\d+` inside a regular
expression. If the observed relation listing was actually generated while
processing this input, then the behavior may indicate that input intended to
be a regular expression is reaching the `psql` command interpreter or
another command-processing layer.

In that case, it should be verified whether other `psql` meta-commands can
also be executed.

## Reproduction query

```sql
WITH products (id, name, price, action) AS
(
VALUES
(1, 'apple', 100, '...')
, (2, 'banana', 200, '...')
, (3, 'orange', 150, '...')
, (4, 'potato', 80, '...')
, (5, 'tomato', 120, '...')
)
SELECT
p.id
, p.name
, p.price
, p.action
FROM products AS p
WHERE regexp_like(p.action, ((?<!-)\d+))
;
```

## Control query

When the regular expression is passed as a proper SQL string literal, the
query should be parsed normally:

```sql
WITH products (id, name, price, action) AS
(
VALUES
(1, 'apple', 100, '...')
, (2, 'banana', 200, '...')
, (3, 'orange', 150, '...')
, (4, 'potato', 80, '...')
, (5, 'tomato', 120, '...')
)
SELECT
p.id
, p.name
, p.price
, p.action
FROM products AS p
WHERE regexp_like(p.action, $$((?<!-)\d+)$$);
```

or:

```sql
WHERE regexp_like(p.action, '((?<!-)\d+)');
```

These control queries do not contain any `psql` meta-command and should not
produce a `List of relations` output.

## Additional observation

The prompt:

```text
db(#
```

indicates that `psql` is waiting for additional input because it considers
the current command incomplete.

The following output:

```text
List of relations
```

does not appear to be generated by the `SELECT` statement itself. It is
normally associated with a `psql` inspection command such as `\d` or `\dt`.

Therefore, the full behavior should be investigated as a possible issue in
command parsing, input sanitization, or interaction between the SQL parser
and the `psql` client parser.

## Expected behavior

The input should be handled consistently as one of the following:

1. A SQL syntax error should be returned because the regular-expression
argument is not a valid SQL string literal; or
2. The expression should be passed to the regular-expression parser and
produce a regular-expression error.

It should not execute or display the result of an unrelated `psql`
meta-command.

Responses

Browse pgsql-docs by date

  From Date Subject
Next Message Laurenz Albe 2026-09-27 12:08:17 Re: log_line_prefix and JSON log format
Previous Message Tom Lane 2026-09-25 22:21:38 Re: log_line_prefix and JSON log format