
Proof-of-concept che dimostra il bypass dell'iniezione SQL CVE-2026-17351 nell'AI Assistant di pgAdmin 4 tramite il differenziale dei lexer sqlparse/PostgreSQL, inclusa la veicolazione di un'iniezione di prompt indiretta.
PoC per CVE-2026-17351, un bypass critico (CVSS 9.0) di SQL injection nell'AI Assistant di pgAdmin 4.
Le versioni 9.13-9.16 di pgAdmin 4 usano la libreria sqlparse di Python per validare che le query SQL generate dagli LLM siano istruzioni singole e di sola lettura. Con standard_conforming_strings = on di PostgreSQL (il default dal PostgreSQL 9.1), sqlparse e PostgreSQL non concordano su come vengono gestite le barre rovesciate all'interno dei literal di stringa. Ciò consente a un attaccante di creare un payload che supera la validazione di sqlparse come singola SELECT ma che in PostgreSQL viene eseguito come quattro istruzioni — inclusa una COMMIT che termina la transazione di sola lettura e successive istruzioni di scrittura.
SELECT '\';COMMIT;CREATE TABLE pwn(x int);SELECT 1 --'
SELECT con un grande literal di stringa → la validazione passaSELECT '\' + COMMIT + CREATE TABLE pwn(x int) + SELECT 1 --'Il payload viene consegnato tramite iniezione indiretta di prompt: l'attaccante lo inserisce all'interno di un oggetto del database (commento di colonna, valore di riga, definizione di vista) che l'AI Assistant legge. Quando un utente legittimo pone una domanda, l'LLM legge i dati avvelenati e li emette come chiamata allo strumento execute_sql_query.
| File | Descrizione |
|---|---|
poc.py | Dimostra il differenziale del lexer: la validazione di sqlparse passa, il protocollo di query semplice esegue più istruzioni, il protocollo di query esteso lo blocca |
prompt_injection_demo.py | Simula l'intera catena di attacco: payload inserito come commento di colonna → LLM simulato lo legge → la validazione passa → esecuzione |
pip install psycopg[binary] sqlparse
È inoltre necessario un'istanza PostgreSQL in esecuzione (14+):
docker run -d --name pg-poc \
-e POSTGRES_PASSWORD=secret \
-e POSTGRES_DB=testdb \
-p 5433:5432 \
postgres:18
# 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
La correzione forza il protocollo di query esteso di psycopg3:
conn.prepare_threshold = 0 sulla connessione dedicata dell'LLMprepare=True a cursor.execute()Questo rende il passo Parse di PostgreSQL l'autorità sui confini delle istruzioni — rifiuta strutturalmente il testo multi-istruzione indipendentemente da come un lexer lato client lo classifica.
Questo PoC è solo per scopi educativi e di test autorizzati.