
إثبات مفهوم يوضح تجاوز حقن SQL (CVE-2026-17351) في المساعد الذكي لـ pgAdmin 4 عبر الفرق في المحلل المعجمي (lexer) بين sqlparse وPostgreSQL، بما في ذلك التسليم غير المباشر لحقن المطالبات (prompt injection).
PoC لثغرة CVE-2026-17351، وهي تجاوز حرج (بدرجة CVSS 9.0) لحقن SQL في المساعد الذكي الخاص بـ pgAdmin 4.
تستخدم إصدارات pgAdmin 4 من 9.13 حتى 9.16 مكتبة sqlparse الخاصة ببايثون للتحقق من أن استعلامات SQL المولّدة بواسطة LLM هي عبارات مفردة للقراءة فقط. في ظل إعداد PostgreSQL standard_conforming_strings = on (الافتراضي منذ PostgreSQL 9.1)، يختلف sqlparse وPostgreSQL حول كيفية التعامل مع الخطوط المائلة العكسية داخل السلاسل النصية. يتيح ذلك للمهاجم صياغة حمولة تمر عبر تحقق sqlparse كعبارة SELECT واحدة ولكنها تُنفَّذ كأربع عبارات في PostgreSQL — بما في ذلك COMMIT ينهي معاملة القراءة فقط وعبارات الكتابة اللاحقة.
SELECT '\';COMMIT;CREATE TABLE pwn(x int);SELECT 1 --'
SELECT واحدة تحتوي سلسلة نصية كبيرة ← يمر الفحصSELECT '\' + COMMIT + CREATE TABLE pwn(x int) + SELECT 1 --'يتم تسليم الحمولة عبر حقن المطالبات غير المباشر: يزرعها المهاجم داخل كائن قاعدة بيانات (تعليق عمود، قيمة صف، تعريف عرض) يقرؤه المساعد الذكي. عندما يطرح مستخدم شرعي سؤالًا، يقرأ 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 على اتصال LLM المخصصprepare=True إلى cursor.execute()هذا يجعل خطوة Parse الخاصة بـ PostgreSQL هي المرجع في تحديد حدود العبارات — فهي ترفض بنيويًا النص متعدد العبارات بغض النظر عن كيفية تصنيف أي محلل معجمي من جانب العميل له.
هذا PoC لأغراض تعليمية واختبارات مصرّح بها فقط.