آخر تحديث: 26 أكتوبر 2026 — هذا التنبيه حيّ وسيُحدَّث مع ظهور معلومات جديدة. راجع قسم «سجل التحديثات» في نهاية المقال.
| الاسم الشائع | Node2Shell |
| المعرّف | CVE-2026-111497 |
| الخطورة | حرجة — CVSS v4.0: 9.2 (Google/NVD) · CVSS v3.1: 9.8 (CSA سنغافورة) · فريق Node.js يصنّفها «مرتفعة» (High) |
| نوع الثغرة | كتابة خارج حدود المخزن (Out-of-Bounds Write / CWE-787) مقترنة بتجاهل قيمة إرجاع خطأ (CWE-252) في مُفكّك ضغط Brotli |
| الأثر | تنفيذ أوامر عن بُعد (RCE)، وتسريب محتوى الذاكرة (قد يكشف بيانات اعتماد وأسرارًا)، وحجب الخدمة (انهيار العملية) |
| المنتج المتأثر | مكتبة Brotli المضمّنة داخل Node.js (الخلل في المكتبة لا في شيفرة Node.js نفسها)، وكذلك Bun وأي برنامج يضمّن Brotli من Google بالإصدارات 1.0.3 حتى 1.2.0 |
| النسخ المتأثرة | Node.js 22.x أقدم من 22.23.4 · 24.x أقدم من 24.22.1 · 26.x أقدم من 26.12.1 · والنسخ منتهية الدعم (25، 23، 21، 20 وأقدم) متأثرة بلا إصلاح · Bun 1.4.3 وأقدم |
| الإصدارات المُصلِحة | Node.js 22.23.4 / 24.22.1 / 26.12.1 · Bun 1.4.4 · مكتبة Brotli 1.0.10 / 1.1.1 / 1.2.1 |
| حالة الاستغلال | شيفرة إثبات مفهوم (PoC) علنية خلال نحو 24 ساعة من الترقيع؛ Imperva أثبتت تنفيذ أوامر على صورة Node.js 24.22.0 الرسمية (Linux arm64)؛ لا دليل معلن على استغلال فعلي، وغير مدرجة في كتالوج CISA KEV حتى 23 أكتوبر 2026 |
| الأولوية | عاجلة — حدّث فورًا حسب درجة التعرّض |
الملخص التنفيذي
في 21 أكتوبر 2026 أصدر مشروع Node.js تحديثات أمنية تعالج ثغرة CVE-2026-111497 — المعروفة باسم Node2Shell — وهي كتابة خارج حدود المخزن في مُفكّك ضغط Brotli الذي تشحنه Node.js ضمن وحدة zlib. يمكن أن يؤدي استغلالها الناجح إلى تنفيذ شيفرة عن بُعد أو تسريب محتوى ذاكرة العملية. وشرط التعرّض هو أن يقوم التطبيق بفكّ ضغط بيانات Brotli يتحكم بها المهاجم.
الخلل ليس في شيفرة Node.js بل في مكتبة Brotli المدمجة؛ لذا فإن معالجته تمر عبر تحديث منصة التشغيل نفسها (أو مكتبة Brotli على مستوى التوزيعة)، لا عبر تحديث حزم npm الخاصة بالتطبيق. وما يجعل الثغرة لافتة هو سرعة الإيقاع الزمني: ظهر أول مستودع عام يتتبّع الثغرة بعد خمس ساعات فقط من نشر الإصلاح، وكانت هناك شيفرة إثبات مفهوم عاملة خلال يوم واحد.
Node2Shell هي الشقيقة المباشرة لثغرتي PHP2Shell اللتين غطّيناهما قبل أيام؛ وكلتاهما تذكّر بأن الثغرات الحديثة كثيرًا ما تسكن المكتبات الأصلية (Native Libraries) تحت منصّات التشغيل، لا في شيفرة التطبيق، وأن كل منصة تضمّن نسخة من المكتبة المعطوبة عليها أن تشحن إصلاحها الخاص.
الخط الزمني
| التاريخ (UTC) | الحدث |
|---|---|
| 14 أكتوبر 2026 | Node.js يُعلن مسبقًا عن الإصدار القادم ويسمّي الفروع المتأثرة بأعلى خطورة «مرتفعة» |
| 21 أكتوبر 2026 — 10:38 | نشر الإصدارات 22.23.4 و24.22.1 و26.12.1 |
| 21 أكتوبر 2026 — 15:47 | ظهور أول مستودع GitHub عام للثغرة، بعد نحو خمس ساعات من الإصلاح |
| 21 أكتوبر 2026 — ~19:27 | مشروع Brotli ينشر الإصدارات 1.0.10 و1.1.1 و1.2.1 وكلها تُدرج CVE-2026-111497 |
| 22 أكتوبر 2026 | نشر سجل CVE من Google بتقييم 9.2 على CVSS v4.0؛ وImperva تنشر بحثًا يُظهر تنفيذ أوامر على Node.js 24.22.0 |
| 23 أكتوبر 2026 | هيئة الأمن السيبراني السنغافورية (CSA) تصدر تنبيهها AL-2026-154 بتقييم CVSS v3.1 يبلغ 9.8 |
التفاصيل التقنية
Brotli صيغة ضغط تدعمها Node.js عبر مُفكّك أصلي (Native) داخل وحدة zlib. يصف سجل الـ CVE تجاوزًا في المخزن داخل الملف c/dec/decode.c، ويسرد تصنيفَي ضعف: كتابة خارج الحدود (CWE-787) وتجاهل قيمة إرجاع (CWE-252).
آلية الخلل: يُعلن التيار المضغوط المُعدّ خصيصًا عن نوع كتلة واحد، ثم يطلب من المُفكّك التبديل إلى نوع كتلة آخر. المُفكّك السليم يتوقف بخطأ عند هذه النقطة، أما المُفكّك غير المُرقَّع فيتجاهل الخطأ ويواصل المعالجة، فيكتب خارج نهاية المخزن. وبتعبير فريق Semgrep، فإن المُفكّك يخلط بين المدخلات الناقصة والمدخلات غير الصالحة، فيستمر في معالجة تيار معطوب كان يجب رفضه.
الإصلاح صغير: اقتبست Node.js تعديلًا من المصدر الأصلي لمكتبة Brotli (الـ commit 0ed4268a) يجعل المُفكّك يفشل فورًا عند طلب تبديل الكتلة بينما يُعلن التيار عن نوع كتلة واحد فقط، مع إضافة ثابت خطأ جديد باسم BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH.
ما المسارات القابلة للوصول؟
Node.js لا تفكّ ضغط Brotli من تلقاء نفسها؛ يصبح التطبيق معرّضًا عندما تقوم شيفرته — أو مكتبة يستخدمها — بفكّ ضغط بيانات Brotli يتحكم بها المهاجم. وقد أكّد فريق Semgrep عدة نقاط دخول:
| المسار | يصل إلى المُفكّك؟ | التفاصيل |
|---|---|---|
Express 5 مع express.json() |
نعم، افتراضيًا | يعتمد Express 5.3.0 على body-parser بإصدار 2.x الذي يفكّ أجسام br، وخيار inflate مفعّل افتراضيًا. (خادم Node.js البسيط لا يفكّ أجسام Brotli الواردة من تلقاء نفسه.) |
Express 4 مع express.json() |
ليس عبر body-parser | إصدار body-parser 1.20.x يعالج deflate وgzip فقط ويردّ 415 لأي ترميز آخر. |
استدعاء fetch() من الخادم |
نعم، للاستجابات التي يؤثر فيها المهاجم | تفكّ Node.js الاستجابة بمُفكّك Brotli كلما احتوت ترويسة Content-Encoding على br. إرسال Accept-Encoding: identity لا يمنع ذلك. الميزات التي تستدعي روابط من المستخدم (مثل Webhooks) أهداف نموذجية. |
استخدام node:zlib مباشرة |
نعم | createBrotliDecompress() معرّضة عندما تتلقى بيانات يتحكم بها المهاجم. |
| Koa (عبر co-body) | نعم | تمرّ أجسام طلبات Brotli عبر co-body إلى الفكّ. ويذكر Semgrep أيضًا @koa/bodyparser وkoa-body وEgg وStrapi. |
Fastify مع @fastify/compress |
نعم | تسجيل الإضافة يضيف فكّ ضغط الطلب قبل مُحلّلات نوع المحتوى في Fastify. |
تُرتَّب الأولوية للمسار الوارد (Inbound): فعند تركيب body-parser بشكل عام يمكن أن يصل إلى كثير من المسارات العامة التي تستقبل أجسامًا. لكن المسار الصادر (Outbound) مهم أيضًا: إذا جلبت خدمتك بيانات من خادم يتحكم به المهاجم، فقد تهاجمك الاستجابة نفسها. وتجدر الملاحظة أن سلامة Express 4 هنا تقتصر على body-parser فقط؛ وسطاء آخرون وأطر عمل وبروكسيات عكسية وشيفرتك الخاصة قد تفكّ Brotli كذلك.
حالة الاستغلال: ما أُثبت مقابل ما زُعم
- تنفيذ أوامر مؤكد (إعداد واحد): أثبتت Imperva تنفيذ شيفرة على صورة Node.js 24.22.0 الرسمية على معمارية Linux arm64، وأشارت إلى أن الاستغلال احتاج عدة محاولات، وانتهى بإنشاء ملف علامة (Marker) على حاويات حديثة البدء دون مُنقّح أو تعديل للملفات التنفيذية، بينما رفض الإصدار المُرقَّع 24.22.1 المدخلات نفسها بخطأ تنسيق. ولم تنشر Imperva شيفرة الاستغلال.
- انهيارات (سهلة التكرار): في 22 أكتوبر أعادت مستودعات PoC عامة إنتاج انهيار العملية على 20.19.5 و22.23.3 و24.22.0 و26.12.0، في حين ترفض الإصدارات المُصلِحة المدخلات نفسها.
- تنفيذ أوامر محلي مشروط: أبلغ فريق عن تنفيذ أوامر محلي في ثلاث من ثلاث محاولات، لكنه احتاج بناءً يُحمّل مكتبة Brotli نظامية غير مُرقَّعة مع تخطيط ذاكرة متوقَّع، وذكر أن التنفيذ الأعمى عن بُعد مع تفعيل عشوائية العناوين (ASLR) لم ينجح.
- تسريب الذاكرة: تذكر Vercel أن الباحثين أظهروا تسريب ذاكرة وتنفيذ أوامر في عملية Node.js على النسخ غير المُرقَّعة من 22.x و24.x و26.x؛ وحتى عند فشل تنفيذ الأوامر قد تكشف الذاكرة المسرّبة بيانات حساسة مثل بيانات الاعتماد.
قراءة متوازنة: التنفيذ الموثوق عن بُعد (RCE) أُعيد إنتاجه في إعداد واحد فقط حتى الآن، ويرى بعض الباحثين أن الأثر الأرجح عمليًا هو حجب الخدمة، كما أن تعليق الإصلاح نفسه يصف الخلل بأنه منخفض الخطورة وغير سهل الاستغلال. والخلاصة العملية: عامِل الانهيار باعتباره النتيجة المرجّحة في كل مكان يفكّ فيه تطبيقك بيانات Brotli قد يتحكم بها المهاجم، واعتبر الحصول على صدفة (Shell) خطرًا معقولًا في تلك المواضع.
ضمن الحزمة نفسها
عالج إصدار 21 أكتوبر نحو عشر ثغرات في منصة Node.js، أربع منها «مرتفعة» الخطورة، تُصلَح جميعها بالترقية إلى الإصدار المُصلِح لفرعك دفعة واحدة. من أبرزها إلى جانب Node2Shell:
| المعرّف | الوصف | الخطورة |
|---|---|---|
| CVE-2026-105482 | اقتطاع dns.resolve للأسماء عند محرف NUL |
مرتفعة |
| CVE-2026-106069 | تجاوز التحقق من اسم المضيف في TLS عند تحليل مضيف بشكل متساهل إلى IP | مرتفعة |
| CVE-2026-105483 | تجاوز التحقق من اسم المضيف في TLS عند استخدام أرقام كاملة العرض (Fullwidth) | مرتفعة |
الإجراءات الموصى بها
1. التحديث (الحل الوحيد الكامل)
- حدّث Node.js إلى 22.23.4 أو 24.22.1 أو 26.12.1. تؤكد Imperva أن تحديث Node.js هو ما يُصلح المُفكّك فعلًا.
- حدّث Bun إلى 1.4.4 أو أحدث أينما استُخدم.
- أعد بناء صور الحاويات من قاعدة مُرقَّعة ثم تحقّق بـ
node --versionداخل الحاوية العاملة. الوسم العائم مثلnode:24يبقى على النسخة القديمة إن أُعيد البناء من ذاكرة تخزين مؤقتة، لذا نفّذdocker pullأولًا، وثبّت الوسم في Dockerfile على 24.22.1 أو أحدث. - تحقّق من مديري الحزم قبل الافتراض: ظلّ Homebrew يشحن نسخًا قديمة بعد نحو عشر ساعات من الإصدار.
- استبدل Node.js 20 وأقدم بـ 22.x أو 24.x؛ فلن يصدر لها إصلاح.
انتبه لحزم التوزيعة: قد تستخدم توزيعات Debian وUbuntu وFedora وRHEL وAlpine مكتبة Brotli النظامية بدل النسخة المضمّنة في Node.js؛ وفي هذه الحالة يصل الإصلاح عبر حزمة Brotli في التوزيعة، ولن يدلّك رقم إصدار Node.js وحده على ما إذا كان النظام مُرقَّعًا. تحقّق من حزمة Brotli كذلك.
2. تقليل التعرّض ريثما تُكمل التحديث
- عطّل فكّ ضغط الطلب حيث تستطيع: في body-parser يرفض
express.json({ inflate: false })الأجسام المضغوطة بالرمز 415 (يرفض gzip أيضًا، فاختبر عملاءك أولًا). - ارفض
Content-Encoding: brعلى أجسام الطلبات عند البروكسي أو موزّع الأحمال حيث لا يرسلها عملاؤك. (اقتراح مجتمعي لا إرشاد رسمي من المورّد، فاختبره أولًا، وهو لا يغطي الاستجابات التي تجلبها خدماتك.) - دقّق استدعاءات
fetch()إلى خوادم لا تتحكم بها، وكل استخدام مباشر لـcreateBrotliDecompress(). - فعّل طبقة WAF إن توفّرت كطبقة إضافية لا كبديل عن الإصلاح (أضافت Imperva قواعد وتنصح بتقييد حركة Brotli غير الموثوقة على المسارات المتأثرة).
3. احتواء نطاق الضرر
- شغّل خدمات Node.js بمستخدم غير مُمتاز وأبقِ الأسرار خارج بيئة العملية قدر الإمكان؛ فتنفيذ الأوامر يقع بصلاحيات عملية Node.js.
- راقب عمليات Node.js المكشوفة للويب بحثًا عن إطلاق أصداف (Shells) أو اتصالات صادرة غير متوقعة.
4. على مستوى البيئة كاملة
- احصر كل نسخة Node.js: الحاويات، ومشغّلات CI، والدوال عديمة الخادم (Serverless)، وخوادم البناء، والأدوات التي تشحن نسخة Node.js خاصة بها.
الكشف والاستجابة
لن يرصد مستشعر زمن التشغيل عملية الكتابة خارج الحدود نفسها، لكنه يرصد ما يفعله الاستغلال الناجح بعدها. ركّز على:
- الجرد أولًا: حدّد المضيفات والأحمال التي تعمل بنسخة Node.js أدنى من الإصدارات المُصلِحة أو بفرع منتهي الدعم.
- ربط الأحداث: اربط انهيار عملية Node.js بتنفيذ برنامج مشبوه يتبعه في الحمل نفسه — فالاستغلال نادرًا ما يكون «نظيفًا»، والمحاولات الفاشلة تُسقط العملية. (نشرت Sysdig قاعدة مُدارة بهذا المعنى: «Node.js Process Crash Followed by In-Place Program Execution».)
- ما بعد الاستغلال: راقب إطلاق أصداف تفاعلية، أو تنزيل برمجيات، أو تعدين عملات، أو سرقة أسرار ورموز سحابية من الحاوية، أو اتصالات صادرة غير معتادة من خوادم الويب.
ماذا يعني هذا لنا في المملكة؟
Node.js حاضرة بقوة في واجهات الـ API والخدمات المصغّرة ومنصّات التجارة الإلكترونية ولوحات الإدارة لدى كثير من الجهات. والسؤال العملي ليس «هل أستخدم Node.js؟» بل «أين تفكّ خدماتي بيانات Brotli قد لا أتحكم بمصدرها؟». ابدأ من هناك: جرد كل نسخة Node.js وBun في بيئتك، ثم رقّع حسب درجة التعرّض بدءًا بالخدمات المكشوفة على الإنترنت والتي تعمل بـ Express 5 أو تستدعي fetch() لعناوين يوفّرها المستخدم، ثم طبّق مبدأ الحد الأدنى من الصلاحيات على ما تبقّى دون ترقيع مؤقتًا. وهذا امتداد طبيعي لما أوصت به الهيئة الوطنية للأمن السيبراني من إدارة الثغرات والأصول وتحصين الأنظمة.
الخلاصة: Node2Shell ليست خللًا في كل خدمة Node.js، بل في الخدمات التي تفكّ بيانات Brotli قد يتحكم بها المهاجم — وExpress 5 بالإعداد الافتراضي يضع عددًا كبيرًا منها في هذه الفئة. الأثر المُثبت حتى الآن هو انهيارات واسعة وتنفيذ أوامر في إعداد ضيّق، فليكن ترتيب الترقيع تبعًا لدرجة الوصول. والأهم: رقّع المنصة نفسها، لا حزم التطبيق، وتحقّق من مكتبة Brotli على مستوى التوزيعة.
المراجع
- Node.js — October 2026 Security Releases (المصدر الرسمي)
- NVD — CVE-2026-111497
- CSA سنغافورة — Critical Vulnerability in Node.js (AL-2026-154)
- Sysdig — Node2Shell: Detecting the Node.js Brotli RCE
- Imperva — Node2Shell: From Brotli Data to Remote Code Execution
- Semgrep — تحليل جذر الخلل في المُفكّك
- Vercel — Node.js Security Advisory
- Aikido — تأثّر Bun بالثغرة
- Tenable — CVE-2026-111497
- سابري — تنبيه PHP2Shell (الثغرة الشقيقة في مُفسّر PHP)
سجل التحديثات
- 26 أكتوبر 2026: النشر الأول للتنبيه بناءً على تحديثات Node.js الأمنية الصادرة في 21 أكتوبر 2026، وتنبيه CSA سنغافورة AL-2026-154، وتحليل Sysdig وImperva.