
pgAdmin 4のAIアシスタントにおける、sqlparse/PostgreSQLレキサーの差分を介したCVE-2026-17351 SQLインジェクション回避を実証する概念実証。間接的なプロンプトインジェクションの配信を含みます。
CVE-2026-17351 の PoC。pgAdmin 4 の AI アシスタントに存在する重大な(CVSS 9.0)SQL インジェクションバイパスです。
pgAdmin 4 バージョン 9.13 から 9.16 は、Python の sqlparse ライブラリを使用して、LLM が生成した SQL クエリが単一の読み取り専用ステートメントであることを検証します。PostgreSQL の standard_conforming_strings = on(PostgreSQL 9.1 以降のデフォルト)では、sqlparse と PostgreSQL は、文字列リテラル内のバックスラッシュの扱いについて見解が異なります。これにより、攻撃者は sqlparse の検証を単一の SELECT として通過する一方、PostgreSQL では 4 つのステートメントとして実行されるペイロードを作成できます。その中には、読み取り専用トランザクションを終了させる COMMIT と、それに続く書き込みステートメントが含まれます。
SELECT '\';COMMIT;CREATE TABLE pwn(x int);SELECT 1 --'
SELECT として認識 → 検証を通過SELECT '\' + COMMIT + CREATE TABLE pwn(x int) + SELECT 1 --' として認識ペイロードは間接プロンプトインジェクションによって配信されます。攻撃者は、AI アシスタントが読み取るデータベースオブジェクト(列コメント、行値、ビュー定義)内にペイロードを仕込みます。正当なユーザーが質問すると、LLM は汚染されたデータを読み取り、それを execute_sql_query ツール呼び出しとして出力します。
| ファイル | 説明 |
|---|---|
poc.py | レキサーの差分を実証: sqlparse の検証は通過するが、単純クエリプロトコルでは複数のステートメントが実行され、拡張クエリプロトコルではブロックされる |
prompt_injection_demo.py | 攻撃チェーン全体をシミュレート: 列コメントとして仕込まれたペイロード → シミュレートされた LLM が読み取る → 検証を通過 → 実行 |
pip install psycopg[binary] sqlparse
実行中の PostgreSQL インスタンス(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
この修正では、psycopg3 の拡張クエリプロトコルを次の方法で強制します:
conn.prepare_threshold = 0 を設定するcursor.execute() に prepare=True を渡すこれにより、ステートメントの境界を決定する権限は PostgreSQL 自身の Parse ステップに移ります。クライアント側のレキサーがどのように分類するかに関係なく、複数ステートメントを含むテキストを構造的に拒否します。
この PoC は教育目的および許可されたテスト目的のみで使用してください。