如何檢查 Node.js 是否受 CVE-2026-111497 影響並修補 Brotli RCE
هل إصدار Node.js لديك مهدد بثغرة Brotli RCE؟ تحقق في دقيقتين
Node.js Brotli RCE 漏洞 CVE-2026-111497 已有活躍利用,22.x、24.x、26.x 的修補版本下限分別為 22.23.4、24.22.1、26.12.1。
文章把版本檢查與實際 Brotli 解碼路徑分開,並比較多種 Node.js 框架及客戶端的行為,呈現判斷漏洞暴露面所需的兩個條件。
هل إصدار Node.js لديك مهدد بثغرة Brotli RCE؟ تحقق في دقيقتين
نفّذ هذا الأمر الآن. إذا كان إصدارك أقل من الحد الأدنى الموضح في الجدول أدناه، فإن ثغرة تنفيذ التعليمات البرمجية عن بُعد (RCE) في مكتبة Brotli الخاصة بـ Node.js (المعرّفة برمز CVE-2026-111497) تنطبق عليك، والمهاجمون يستغلونها بالفعل.
node -v
| خط الإصدار | الإصدارات المصابة | تم الإصلاح بدءاً من | أحدث إصدار (5 نوفمبر 2026) |
|---|---|---|---|
| 26.x | أقل من 26.12.1 | 26.12.1 | 26.13.0 |
| 24.x | أقل من 24.22.1 | 24.22.1 | 24.22.2 |
| 22.x | أقل من 22.23.4 | 22.23.4 | 22.23.4 |
| 25.x, 20.x, older | بلغت نهاية العمر الافتراضي: لم تُرقّع ولم تُقيّم | لا يوجد إصلاح متوفر | انتقل إلى 24 أو 26 |
وللتأكد عبر مؤشر ثانٍ، يمكنك الاستعلام من الملف التنفيذي مباشرة:
node -p "require('node:zlib').constants.BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH"
أضاف التحديث هذا الثابت. لقد قمنا بتشغيل الأمر على تسع نسخ رسمية لنظام macOS من خطوط الإصدار الثلاثة المدعومة: ظهرت القيمة -17 في كل إصدار مُصحح، بينما ظهرت القيمة undefined في جميع الإصدارات الأقدم. ومع ذلك، اعتمد أولاً على node -v، لأن بعض توزيعات لينكس التي تطبق الترقيعات بأثر رجعي قد لا تضيف هذا الثابت.
تجاهل process.versions.brotli؛ فقد أرجع القيمة 1.2.0 في كل من 24.21.0 و24.22.1، والقيمة 1.1.0 في كل من 22.23.3 و22.23.4. قام فريق Node.js بدمج الإصلاح دون تغيير رقم الإصدار المُعلن، لذا لا يمكن لهذا الحقل أن يوضح ما إذا كان نظامك قد تلقى الترقيع أم لا.
ملخص سريع (TL;DR)
| السؤال | الإجابة |
|---|---|
| ما هي هذه الثغرة؟ | كتابة خارج الحدود في مفكك ترميز Brotli المدمج في Node.js، وتُعرف أيضاً باسم Node2Shell أو HTTP2Shell |
| التأثير | انهيار التطبيق، أو تسريب بيانات من الذاكرة، أو تنفيذ تعليمات برمجية عن بُعد |
| مستوى الخطورة | مرتفع وفقاً لـ Node.js؛ وحرج بدرجة 9.8 (CVSS 3.1) وفقاً لـ NVD |
| هل يتم استغلالها حالياً؟ | نعم. أدرجتها وكالة CISA في كتالوج الثغرات المستغلة المعروفة بتاريخ 27 أكتوبر 2026 |
| هل تتطلب تسجيل الدخول؟ | لا، وفقاً لمتجه تقييم NVD وتحليل شركة Akamai |
| من المعرّض للخطر؟ | التطبيقات التي تفك ترميز بيانات Brotli غير موثوقة: مثل نصوص طلبات Express 5، واستجابات fetch()، والاستدعاءات المباشرة لمكتبة node:zlib
|
| الحل | ترقية بيئة التشغيل، وإعادة بناء صور الحاويات، وإعادة تشغيل العمليات |
| هل توجد حلول بديلة؟ | لم يذكر التحذير الأمني أي حل بديل. الإجراءات المؤقتة أدناه تقلل من مساحة التعرض لكنها لا تغطي كل شيء |
أفادت شركة ELLIO برصد حركة استغلال للثغرة عبر أجهزة الاستشعار الخاصة بها بحلول 26 أكتوبر، أي بعد خمسة أيام فقط من طرح الإصلاح. واستهدفت الحمولة الضارة التي تم التقاطها إصدار Node.js 24.22.0 على معمارية x86-64. ورغم أن المرحلة الأخيرة من تلك الحمولة فشلت أثناء اختبارات ELLIO، إلا أن الشركة أكدت إمكانية تنفيذ التعليمات البرمجية نفسها على إصدارات 24.22.0 الرسمية دون تعديل. وقد منحت وكالة CISA الوكالات الفيدرالية الأمريكية مهلة حتى 10 نوفمبر لاتخاذ الإجراءات اللازمة، وصنفت استخدام برمجيات الفدية بأنه "غير معروف". وأظهرت بيانات القياس عن بُعد لشركة Akamai أن 61% من الشبكات كانت لا تزال تشغّل إصدارات مصابة حتى 26 أكتوبر.
شرح ثغرة Node2Shell: كيف يعمل خلل Brotli؟
تتمثل ثغرة Node2Shell في خطأ كتابة خارج الحدود داخل مفكك ترميز Brotli المدمج في بيئة تشغيل Node.js. حيث يؤدي تدفق مضغوط تالف إلى قيام مفكك الترميز بالكتابة بعد نهاية مخزن مؤقت داخلي بحجم ثمانية بايتات، مما يتسبب في إتلاف ذاكرة العملية. وقد يؤدي ذلك إلى انهيار التطبيق، أو تسريب بيانات من الذاكرة، أو تنفيذ تعليمات برمجية يتحكم بها المهاجم على خادمك.
يعود السبب الجذري إلى تصنيف خاطئ لحالة الخطأ؛ إذ تم تفسير تبديل كتل غير صالح على أنه "أحتاج إلى مزيد من المدخلات" بدلاً من "هذه البيانات تالفة"، مما دفع مفكك الترميز التدفقي إلى الاستمرار في إلحاق البايتات بذلك المخزن المؤقت الصغير.
يكمن الخلل في مكتبة Brotli التابعة لشركة Google، من الإصدار 1.0.3 حتى 1.2.0، لذا فإن المشكلة لا تقتصر على Node.js فحسب. وقامت Node.js بإصلاح نسختها عبر دمج التعديل البرمجي 0ed4268a من المصدر الأساسي ضمن إصدار 24.22.1 والإصدارات الشقيقة المقابلة له. وكان باحثا أمان OpenAI Codex، خاي تران وسيلفي ماير، هما من أبلغا عن الثغرة.
لن تتمكن أدوات فحص التبعيات لديك من اكتشاف هذه الثغرة، لأن مفكك الترميز مدمج مباشرة في بيئة التشغيل وليس كحزمة مستقلة. فعلى سبيل المثال، أظهر الأمر npm install وجود 0 ثغرات أمنية لمشروعنا التجريبي المبني على Express 5 أثناء تشغيله على إصدار Node.js 24.15.0 غير المُرقّع.
من هم المعرّضون للخطر؟
إن وجود بيئة تشغيل مصابة يمثل نصف شروط التعرض للخطر فقط، أما النصف الآخر فهو وجود مسار يمرر بيانات Brotli غير موثوقة إلى مفكك الترميز. لقد اختبرنا كل مسار على Node.js 24.22.1 عن طريق إرسال نص طلب غير صالح وغير ضار (النص not-valid-brotli) مع ترويسة Content-Encoding: br، وكذلك عبر تقديم بيانات Brotli صالحة لكل عميل.
| المسار | الإصدار الذي تم اختباره | هل يشغّل مفكك الترميز؟ | النتيجة الملاحظة |
|---|---|---|---|
Express 5 express.json()
|
5.3.0 (body-parser 2.4.0) | نعم، افتراضياً | 400، "Decompression failed" |
Express 4 express.json()
|
4.22.3 (body-parser 1.20.9) | لا | 415، ترميز غير مدعوم |
Koa @koa/bodyparser
|
6.1.0 | نعم، افتراضياً | 500، خطأ BrotliDecoder في السجل |
Fastify مع @fastify/compress
|
9.3.0 | نعم، بمجرد تسجيل الإضافة | 400، FST_CP_ERR_INVALID_CONTENT
|
| Fastify بدون إضافات | 5.12.8 | لا | 400، بيانات JSON غير صالحة |
خادم node:http المباشر أو http.get
|
24.22.1 | لا | تمر البايتات الخام كما هي |
دالة fetch() المدمجة |
24.22.1 | نعم، دائماً | تم فك ترميز الاستجابة |
| axios, got, node-fetch | 1.21.0, 16.2.0, 3.3.2 | نعم، افتراضياً | تم فك ترميز الاستجابة |
zlib.brotliDecompress*, createBrotliDecompress
|
أي إصدار | نعم | هذه هي واجهة برمجة تطبيقات مفكك الترميز |
هناك نتيجتان تستحقان التدقيق؛ الأولى هي أن دالة fetch() فكّت ترميز Brotli حتى عندما أرسل الطلب ترويسة Accept-Encoding: identity، لأنها تتبع ترويسة الاستجابة وليس ما طلبته تحديداً. وهذا يعني أن أي خادم خارجي يستدعيه تطبيقك قادر على الوصول إلى مفكك الترميز، مما يجعل أدوات اختبار الـ webhooks أو معاينة الروابط أو استيراد عناوين URL عُرضة للخطر. النتيجة الثانية هي أن استجابة الخطأ 400 وحدها لا تثبت شيئاً؛ فكل من Express 5 وFastify بدون إضافات يُرجع رمز 400، ولكن Express 5 وحده هو من قام بتشغيل مفكك الترميز بالفعل. لذا، تحقق دائماً من رسالة الخطأ المصاحبة.
يمكنك التحقق من المسارات المعرضة لديك باستخدام هذه الأوامر الثلاثة:
# Direct decoder use
grep -rnE "brotliDecompress|createBrotliDecompress" src/
# Parsers that decode request bodies
npm ls express body-parser @koa/bodyparser @fastify/compress
# Base images and pinned versions
grep -rnE "^FROM .*node" --include='Dockerfile*' .
تذكر أن استدعاءً جديداً واحداً لدالة fetch() كفيل بتغيير هذه الإجابات بالكامل، لذلك فإن وصف "غير معرّض حالياً" يعني أيضاً أنه يتوجب عليك الترقيع فوراً.
كيفية ترقيع ثغرة CVE-2026-111497
قم بالترقية إلى أحدث بناء ضمن خط الإصدار الذي تستخدمه، وليس إلى الحد الأدنى فقط. كانت جميع هذه المصادر توفر الإصدارات المصححة اعتباراً من 5 نوفمبر:
| طريقة التثبيت | الإجراء المطلوب |
|---|---|
| nvm | nvm install 24 && nvm alias default 24 |
| Homebrew |
brew upgrade node (أو node@24، node@22) |
| Docker |
FROM node:24.22.2-slim، ثم نفّذ docker build --pull
|
| حزم توزيعات Linux | اتبع التحذير الأمني الخاص بتوزيعتك، حيث قد تقوم بتطبيق الإصلاح بأثر رجعي تحت رقم إصدار أقدم |
| CI | حدّث .nvmrc وengines وnode-version، ثم أعد البناء |
| البيئات السحابية الخادمة | سجّل قيمة process.version من دالة منشورة للتأكد؛ ولا تفترض أن المنصة قد قامت بتحديثها تلقائياً |
ثم عالج الثغرتين الشائعتين اللتين يقع فيهما الكثيرون:
- أعد تشغيل كل شيء: تحتفظ العمليات قيد التشغيل بالملف التنفيذي القديم في الذاكرة، لذا فإن الترقية على القرص لن تغير شيئاً حتى تقوم أدوات مثل pm2 أو systemd أو نظام إدارة الحاويات لديك بإعادة تشغيلها.
- أعد بناء ما قمت بنشره: تحتفظ صور الحاويات القديمة ببيئة التشغيل القديمة، كما أن الصور المثبتة عبر المعرّف الفريد تتطلب فحصاً أمنياً للصورة لأن وسم الإصدار لن يكشف لك الحقيقة.
واختتم بإجراء الفحوصات المذكورة في بداية هذا المقال داخل الحاوية المنشورة، ثم على أجهزة تشغيل CI وأجهزة المطورين. ولمعرفة أحدث بناء أمني لكل خط إصدار:
curl -s https://nodejs.org/dist/index.json | jq -r '[.[] | select(.security == true and (.version | test("^v(22|24|26)\\.")))] | group_by(.version | split(".")[0]) | .[] | max_by(.date) | "\(.version) \(.date)"'
هل ما زلت تستخدم الإصدار 20 أو 25؟ لا يتوفر أي بناء مُصلح لك. راجع خطة انتهاء دعم Node.js 20 وبادر بالترقية.
إجراءات التخفيف من ثغرة Brotli في Node.js إذا لم تتمكن من الترقيع اليوم
تمنحك هذه الخطوات بعض الوقت، ولكن لا شيء منها يغني عن الترقية الفعلية.
-
رفض ترميز
brعند أطراف الشبكة: احظر ترويسةContent-Encoding: brعند الخادم الوكيل أو موزع الأحمال، مع مراعاة عدم حساسية الأحرف واكتشافها داخل القوائم مثلgzip, br. - رفض الترميز داخل التطبيق: أضف هذا الجزء البرمجي قبل معالجات نصوص الطلبات، وقد أرجع رمز الاستجابة 415 في اختبارنا على Express 5:
app.use((req, res, next) => {
const encoding = req.headers['content-encoding'] || '';
if (/\bbr\b/i.test(encoding)) return res.status(415).end();
next();
});
-
تعطيل فك الضغط التلقائي: أرجع الإعداد
express.json({ inflate: false })رمز 415 لنفس الطلب. ولكنه يرفض أيضاً الطلبات المضغوطة بـ gzip، لذا تحقق من توافق عملائك أولاً. -
التحكم في الاستجابات الصادرة: تقبل مكتبة axios الخيار
decompress: false، والذي أبقى البايتات دون فك ترميز في اختبارنا. أما دالةfetch()فلا توفر خياراً قياسياً لتعطيل فك الضغط، لذا يجب تقييد المضيفين الذين يمكنها الاتصال بهم عبر قائمة مسموح بها وقواعد حركة البيانات الصادرة. - تقليل نطاق الضرر: اعزل خدمات Node.js في بيئات منفصلة، وقيّد صلاحيات الوصول إلى ملفات تفريغ الذاكرة عند الانهيار، حيث أشارت ELLIO إلى أن انهيار التطبيق قد يكشف بيانات الذاكرة الحساسة فيها.
راقب بدقة ما لاحظته ELLIO أولاً: دفعات مفاجئة من نصوص الطلبات المرمزة بـ Brotli لاستكشاف وتحديد المضيفين الذين يقومون بفك ترميزها. لذا، فإن ظهور حركة بيانات غير متوقعة تحمل Content-Encoding: br على واجهة برمجة تطبيقات JSON، أو حدوث ارتفاع مفاجئ في انهيار عمليات التشغيل، يستدعي التحقيق الفوري.
تأكد من سلامة واجهة برمجة التطبيقات بعد الترقية: دع وكيل الذكاء الاصطناعي يتولى الأمر
يمكن للانتقال بين إصدارات بيئة التشغيل أن يغيّر سلوك بروتوكولات TLS وDNS وHTTP، وقد شملت تحديثات شهر أكتوبر الجوانب الثلاثة معاً. لا تقارن الفروقات يدوياً؛ بل دع وكيل البرمجة لديك يشغّل أداة Apidog CLI قبل الترقية وبعدها، ثم يقدّم تقريراً بما تغيّر.
npm install -g apidog-cli@latest
apidog login --with-token <YOUR_TOKEN>
npx -y skills add https://apidog.com # pick your agent when prompted
وجّه هذا الطلب إلى وكيلك البرمجي:
Run Apidog test suite <id> in project <id> against staging and save the
results to reports/before. After I upgrade Node.js, add a test case for
POST /orders that sends the plain text "not-valid-brotli" with
Content-Encoding: br, asserts a 4xx status, then checks GET /health
returns 200. Rerun the suite to reports/after and list every request
whose result changed.
سيقوم الوكيل بتشغيل هذه الأوامر:
apidog run --test-suite <id> --project <id> -e <envId> -r cli,junit --out-dir reports/before
apidog cli-schema get test-case-create
apidog cli-schema validate test-case-create --file case.json
apidog test-case create --project <id> --file case.json
apidog run --test-case <caseId> --project <id> -e <envId> -r cli,json
apidog run --test-suite <id> --project <id> -e <envId> -r cli,junit --out-dir reports/after
تُعد حالة الاختبار الإضافية هذه فحصاً لسلامة النظام وليست هجوماً استغلالياً؛ فنص الطلب هو مجرد نص عادي، وقد فشل بنفس خطأ الحشو في كل من الإصدارات المصابة والمُصلحة في اختبارنا. ومع ذلك، فإن هذا الفحص يكشف عن ثغرة حقيقية في التعامل مع الأخطاء؛ إذ رد خادم Koa التجريبي برمز 500 بسبب عدم معالجة خطأ فك الترميز، في حين يجب على أي واجهة برمجة تطبيقات عامة أن ترد برمز من فئة 4xx. احرص على تشغيل هذا الاختبار في بيئة التجارب فقط.
يوضح مرجع أمر التشغيل جميع الخيارات المتاحة، بينما يشرح دليل CI/CD كيفية دمج تشغيل اختبارات JUnit في مسار النشر التلقائي لديك. وتدعم باقة Apidog المجانية ما يصل إلى 4 مستخدمين.
أهمية موعد 11 نوفمبر القادم
أعلن مشروع Node.js مسبقاً عن إصدار أمني قادم لخطوط الإصدار 26.x و24.x و22.x في 11 نوفمبر 2026 أو بعده بقليل، وسيكون أعلى تصنيف للخطورة فيه هو "مرتفع" مجدداً. ولم يتم الكشف عن أرقام CVE علناً بعد. يوضح دليل إصدار نوفمبر الخاص بنا كيفية الاستعداد لذلك.
قم بترقيع ثغرة Brotli الآن بدلاً من تأجيلها ودمجها مع ذلك التحديث القادم؛ فالمعلومات التفصيلية عن الخلل أصبحت متاحة للعامة وحركة استغلاله نشطة بالفعل اليوم. كما أن عملية الترقية التي تجريها هذا الأسبوع تعد تدريباً عملياً للترقية التالية: نفس حصر الأصول، ونفس إعادة بناء الصور، ونفس مجموعة الاختبارات. لقد سارت ثغرات سابقة مثل PHP2Shell وReact2Shell على نفس النمط تماماً.
الأسئلة الشائعة (FAQ)
هل يتم استغلال ثغرة CVE-2026-111497 حالياً؟ نعم. أضافتها CISA إلى كتالوج الثغرات المستغلة المعروفة في 27 أكتوبر 2026 تحت Google Brotli، كما سجلت ELLIO محاولات استغلال نشطة بحلول 26 أكتوبر.
هل تصنيفها مرتفع أم حرج؟ كلا التصنيفين صحيحان وواقعيان؛ إذ تصنفها Node.js بدرجة خطورة مرتفعة، بينما تمنحها قاعدة بيانات NVD درجة خطورة حرجة 9.8 وفقاً لمقياس CVSS 3.1، كما تمنحها Google تقييم 9.2 وفقاً لمقياس CVSS 4.0. ضع خطتك دائماً بناءً على حقيقة أنها مستغلة بالفعل.
أستخدم Express 4، فهل أنا بأمان؟ لا تصل نصوص الطلبات الواردة إلى تطبيقك إلى مفكك الترميز، لكن استدعاءات fetch() وaxios والمكتبة المباشرة node:zlib لا تزال تصل إليه. وعلاوة على ذلك، أصلح نفس الإصدار تسع ثغرات CVE أخرى، لذا ينبغي عليك الترقية في جميع الأحوال.
هل يتأثر إصدار Node.js 20؟ لا يقيّم مشروع Node.js خطوط الإصدار التي بلغت نهاية دعمها، ولن تتلقى أي إصلاح. تعامل مع الإصدارين 20.x و25.x على أنهما غير مُرقّعين وغير مُقيّمين، وبادر بالترقية إلى إصدار مدعوم.
هل تؤثر هذه الثغرة على أنظمة أخرى غير Node.js؟ نعم. يغطي التحذير الأمني على GitHub حزمتي brotli وbrotlicffi على PyPI، كما أعلن المطورون عن إصلاحات لـ Bun 1.4.4 و.NET. احرص على تحديث كل مفكك ترميز على حدة، لأن ترقية Node.js لا تشمل سوى النسخة المدمجة بها فقط.
來源:DEV Community · dev.to


