Share
## https://sploitus.com/exploit?id=B1D1E25F-BBB1-5A30-95D8-EC0DD6E59C87
# CVE-2026-17351 โ€” pgAdmin 4 AI Assistant Read-Only Bypass via Lexer Differential

PoC for CVE-2026-17351, a critical (CVSS 9.0) SQL injection bypass in pgAdmin 4's AI Assistant.

## Vulnerability Summary

pgAdmin 4 versions 9.13 through 9.16 use Python's `sqlparse` library to validate that LLM-generated SQL queries are single, read-only statements. Under PostgreSQL's `standard_conforming_strings = on` (the default since PostgreSQL 9.1), `sqlparse` and PostgreSQL disagree about how backslashes inside string literals are handled. This allows an attacker to craft a payload that passes `sqlparse`'s validation as a single `SELECT` but executes as four statements in PostgreSQL โ€” including a `COMMIT` that ends the read-only transaction and subsequent write statements.

## Payload

```sql
SELECT '\';COMMIT;CREATE TABLE pwn(x int);SELECT 1 --'
```

- **sqlparse** sees one `SELECT` with a big string literal โ†’ validation passes
- **PostgreSQL** sees: `SELECT '\'` + `COMMIT` + `CREATE TABLE pwn(x int)` + `SELECT 1 --'`

## Delivery

The payload is delivered via **indirect prompt injection**: the attacker plants it inside a database object (column comment, row value, view definition) that the AI Assistant reads. When a legitimate user asks a question, the LLM reads the poisoned data and emits it as an `execute_sql_query` tool call.

## Files

| File | Description |
|---|---|
| `poc.py` | Demonstrates the lexer differential: sqlparse validation passes, simple query protocol executes multiple statements, extended query protocol blocks it |
| `prompt_injection_demo.py` | Simulates the full attack chain: payload planted as a column comment โ†’ simulated LLM reads it โ†’ validation passes โ†’ execution |

## Requirements

```bash
pip install psycopg[binary] sqlparse
```

You also need a running PostgreSQL instance (14+):

```bash
docker run -d --name pg-poc \
    -e POSTGRES_PASSWORD=secret \
    -e POSTGRES_DB=testdb \
    -p 5433:5432 \
    postgres:18
```

## Usage

```bash
# Main PoC โ€” lexer differential demonstration
python3 poc.py

# Prompt injection delivery demo
python3 prompt_injection_demo.py

# Custom connection parameters
python3 poc.py --host 10.0.0.5 --port 5432 --user postgres --password mypw
```

## The Fix (pgAdmin 9.17)

The fix forces psycopg3's **extended query protocol** by:
1. Setting `conn.prepare_threshold = 0` on the LLM's dedicated connection
2. Passing `prepare=True` to `cursor.execute()`

This makes PostgreSQL's own `Parse` step the authority on statement boundaries โ€” it structurally rejects multi-statement text regardless of how any client-side lexer classifies it.

## References

- CVE: https://nvd.nist.gov/vuln/detail/CVE-2026-17351
- GitHub Issue: https://github.com/pgadmin-org/pgadmin4/issues/10192
- Fix Commit: https://github.com/pgadmin-org/pgadmin4/commit/ef76102bcd1cdb544eb9b4ef18d3382f22b76752
- Original CVE (CVE-2026-12045): https://nvd.nist.gov/vuln/detail/CVE-2026-12045
- Reporter: Kai Aizen (SnailSploit)

## Disclaimer

This PoC is for educational and authorized testing purposes only.