ما الذي يصلحه هذان التنبيهان
يستهدف التنبيهان ext/openssl، الامتداد المسؤول عن تشفير TLS في تدفقات PHP. لا يتعلق الأمر بزوار موقعكم، بل بالاتصالات التي يفتحها كود PHP لديكم نحو الخارج، مثل file_get_contents('https://…') أو fopen على رابط https أو stream_socket_client على tls://.
في هذه الحالات تتحقق PHP من أن الشهادة التي يقدّمها الخادم البعيد تطابق اسم المضيف المطلوب. هذا هو الخيار verify_peer_name، وهو مفعّل افتراضيًا. تقع الثغرتان معًا في هذا الفحص. يصف تنبيه CVE-2026-91769 (GHSA-vvx9-73fr-5jjx) تحققًا متساهلًا أكثر مما ينبغي، ويصف تنبيه CVE-2026-91767 (GHSA-xr7j-rvgx-xq5p) قراءة خارج حدود الذاكرة المؤقتة عند مقارنة الأسماء ذات حرف البدل. نُشر التنبيهان في اليوم نفسه، 24 سبتمبر 2026، وتصلحهما الإصدارات نفسها.
الخلاصة في سبع نقاط
- CVE-2026-91769 — خطورة متوسطة، درجة CVSS 3.1 تساوي 4.3. يفحص التحقق من اسم النظير حقول
subjectAltNameأولًا، ثم يعود إلى الاسم الشائع (Common Name) حتى حين تعرض الشهادة SAN من نوع DNS لا يطابق الاسم المطلوب. - CVE-2026-91767 — خطورة متوسطة، درجة CVSS 3.1 تساوي 6.5 (CWE-122). في الدالة
php_openssl_matches_wildcard_name()يؤدي نقص في الطول يُمرَّر إلىmemchr()إلى قراءة خارج حدود الذاكرة المؤقتة حين يحتوي اسم حرف البدل في الشهادة على أحرف حرفية أكثر من المضيف الذي يجري التحقق منه. - الإصدارات المصحَّحة — PHP 8.2.34 و8.3.35 و8.4.26 و8.5.11 للثغرتين معًا. يظهر الإصداران 8.4.26 و8.5.11 في سجل تغييرات PHP بتاريخ 24 سبتمبر 2026.
- من المعني — العملاء الذين يعتمدون على القيمة الافتراضية للخيار
verify_peer_nameعبرfile_get_contents()وfopen()وstream_socket_client()علىhttps://وtls://. - الحل المؤقت — لا يذكر التنبيه أي حل. تعطيل التحقق ليس حلًا، بل ثغرة إضافية.
- الفروع 8.1 وما قبلها — منتهية الدعم ولا يوجد إصلاح من المشروع. قد توجد إصلاحات من التوزيعة أو backports من أطراف ثالثة: تحققوا حزمة بحزمة.
- الاستغلال — لم نجد في المصادر التي رجعنا إليها أي استغلال مرصود لهاتين الثغرتين.
ما تتيحه هاتان الثغرتان وما لا تتيحه
تتيح CVE-2026-91769 انتحال مضيف. يمكن لشهادة يعتمدها عميلكم لمضيف ما أن تُستعمل للتظاهر بمضيف آخر إذا كان اسمها الشائع (CN) يتضمن الاسم المستهدف. تنص RFC 6125 على تجاهل CN عند وجود SAN من نوع DNS، ولم تكن PHP تفعل ذلك. يرى التنبيه أن الحالة تهم خصوصًا البنية المفتاحية الخاصة (PKI)، أي سلطة داخلية تصدر شهادات لخدمات كثيرة.
تتيح CVE-2026-91767 إسقاط عميل PHP. يستطيع خادم خبيث، أو خادم بسلطة موثوقة، إحداث القراءة خارج الحدود أثناء التحقق، وهذا حجب للخدمة. يوضح التنبيه أن النتيجة لا تؤثر إلا في قرار القبول أو الرفض ولا تُرجع أي محتوى من الكومة. تحفظ صريح: يُقدّر متجه CVSS السرية بدرجة عالية والإتاحة بلا تأثير، وهذا لا ينسجم مع نص الأثر. نشير إلى ذلك دون أن نحسمه.
ما لا تتيحانه. لا يصف التنبيه أي تنفيذ للكود. ولا تُفعَّل أي منهما بطلب من زائر يصل إلى موقعكم. المتجهان كلاهما من نوع الشبكة المجاورة (AV:A): يجب أن يكون المهاجم قريبًا من الاتصال، لا في أي مكان على الإنترنت.
مصنّفتان متوسطتين: هل الأمر عاجل؟
جواب صريح: لا شيء في المصادر التي رجعنا إليها يدل على أن هاتين الثغرتين تُستغلان. ولا نؤكد أكثر من ذلك. لا تُقارنان بـ PHP2Shell (CVE-2026-109618 وCVE-2026-109619) التي تستهدف المفسِّر نفسه وتُفعَّل بطلب HTTP مجهول. نعالج تلك الثغرة على حدة في مقالنا عن PHP2Shell؛ وآخر إصدار من فرعكم، وهو ما يطلب منكم ذلك المقال تثبيته، يتضمن هذه الإصلاحات أيضًا.
فالاستعجال متدرج. إنه حقيقي إذا كان الكود لديكم يستدعي عناوين خارجية عبر تدفقات PHP (واجهات الدفع، وwebhooks الصادرة، واستيراد الخلاصات، والتحقق من التراخيص) أو خدمات داخلية تأتي شهاداتها من PKI خاصة. وهو أقل بكثير لموقع تعريفي لا يجري أي استدعاء صادر. وفي الحالتين يبقى الإصلاح ضمن الفرع نفسه: أدرجوه في أقرب نافذة صيانة بدل تأجيله دون تاريخ.
قياس تعرضكم في أربع خطوات
اقرؤوا إصدار PHP الذي يُقدَّم فعليًا
على الخادم، نفّذوا
php -r 'echo PHP_VERSION, PHP_EOL;'. لا تعتمدوا علىOPENSSL_VERSION_TEXT: فالمُصحَّح ليس مكتبة OpenSSL الخاصة بالنظام بل كود الامتداد، أي إصدار PHP. انتبهوا، فقد يختلف سطر الأوامر عما تقدمه مواقعكم: على خادم يستضيف عدة فروع، اقرؤوا أيضًا إصدار كل مجمّع PHP-FPM (خطوة التحقق أدناه). في cPanel يُقرأ الإصدار لكل نطاق، انظروا دليلنا عن محدد إصدار PHP.ابحثوا عن الاستدعاءات التي تمر عبر تدفقات PHP
اعرضوا الاستدعاءات الصادرة التي تحمل رابطًا مكتوبًا في الكود:
grep -rnE "(file_get_contents|fopen)\(\s*['\"]https?://|stream_socket_client\(\s*['\"]tls://" /var/www --include='*.php'. في استضافة cPanel استبدلوا/var/wwwبـ/home. أكملوا بالاستدعاءات التي يأتي رابطها من متغير:grep -rnE "(file_get_contents|fopen|stream_socket_client)\(\s*\$" /var/www --include='*.php'. فكّروا في إضافات WordPress ومجلدvendor: كثيرًا ما تختبئ الاستدعاءات الصادرة هناك.حدّدوا حالات التحقق المعطَّل أصلًا
نفّذوا
grep -rn "verify_peer_name" /var/www --include='*.php'. القيمةfalseتعني أنه لا يُتحقق من أي اسم مضيف: هذا الكود معرّض لأكثر بكثير من هذين التنبيهين، أيًّا كان إصدار PHP. أصلحوه قبل كل شيء.صنّفوا مواقعكم
يكون الموقع أولوية إذا اجتمع فيه فرع دون الحد الأدنى في الجدول التالي واستدعاءات صادرة عبر التدفقات. لا يذكر التنبيه الاستدعاءات المنفذة عبر امتداد cURL، فهو يعدّد تدفقات PHP. يستعمل WordPress ومعظم مكتبات HTTP عادةً cURL عند توفره، لكنها تعود إلى التدفقات في غيابه: لا تستبعدوها دون تحقق.
أي إصدار تثبّتون بحسب فرعكم
مرّر الجدول أفقيًا
| فرع PHP | الحد الأدنى المصحَّح | الحالة |
|---|---|---|
| 8.5 | 8.5.11 | مصحَّح. ثبّتوا آخر إصدار متاح من 8.5. |
| 8.4 | 8.4.26 | مصحَّح. ثبّتوا آخر إصدار متاح من 8.4. |
| 8.3 | 8.3.35 | مصحَّح. ثبّتوا آخر إصدار متاح من 8.3. |
| 8.2 | 8.2.34 | مصحَّح. خطّطوا للخروج من هذا الفرع، انظروا قائمة التحقق المرتبطة في آخر المقال. |
| 8.1 وما قبله (من 5.6 إلى 8.1) | لا يوجد إصدار من المشروع | منتهي الدعم. إصلاح من التوزيعة أو backport من طرف ثالث يجب التحقق منه، وإلا فالترحيل. |
تطبيق الإصلاح بحسب بيئتكم
Debian وUbuntu
حدّثوا الفهرس بـ
sudo apt update، ثم حزم فرعكم بـsudo apt install --only-upgrade 'php8.3*'(استبدلوا 8.3 بفرعكم). لمعرفة المعلّق:apt list --upgradable 2>/dev/null | grep -i php. كثيرًا ما تصلح التوزيعات عبر backport دون تغيير رقم المشروع: اقرؤوا سجل الحزمة بـapt changelog php8.3-cli | grep -i CVE-2026-91769. مع مستودع طرف ثالث مثل Sury تنطبق الأوامر نفسها.RHEL وAlmaLinux وRocky Linux
نفّذوا
sudo dnf update 'php*'. إذا كنتم تستعملون تدفق وحدات فالفرع يتبع الوحدة المفعّلة: يعرضهاdnf module list --enabled php. ثم تحققوا من السجل بـrpm -q --changelog php-cli | grep -i CVE-2026-91769. مع مستودع طرف ثالث تتغير أسماء الحزم: كيّفوا النمط مع ما يعيدهrpm -qa 'php*'.cPanel: EasyApache 4 ومحدد PHP
فروع EasyApache 4 حزم باسم
ea-php83وea-php84وهكذا. إذا كان لديكم صلاحية root فاعرضوها بـrpm -qa 'ea-php*' | sortثم حدّثوها بـsudo dnf update 'ea-php*'. اقرؤوا السجل بـrpm -qa --changelog 'ea-php83*' | grep -i CVE-2026-91769والإصدار الفعلي بـ/opt/cpanel/ea-php83/root/usr/bin/php -v. في الاستضافة المشتركة يتولى المضيف التحديث: دوركم أن تتحققوا، في محدد PHP بـ cPanel (MultiPHP Manager أو Select PHP Version على CloudLinux)، من أن كل نطاق يعمل على فرع مصحَّح.Docker
لا تُصلَح الصورة في مكانها: أعيدوا بناءها مع سحب القاعدة المحدَّثة بـ
docker build --pull --no-cache -t your-image .، أوdocker compose build --pull --no-cacheمع Compose، ثم أعيدوا التشغيل بـdocker compose up -d. تحققوا من النتيجة داخل الحاوية بـdocker run --rm your-image php -v. لا تتقدم وسمة عائمة مثلphp:8.4-fpmإلا إذا أُعيد بناء الصورة الأصلية: الرقم المعروض هو المرجع لا اسم الوسم.أعيدوا تشغيل خدمات PHP
يحتفظ PHP-FPM وApache بالكود القديم في الذاكرة ما لم يُعاد تحميلهما. على Debian أو Ubuntu:
sudo systemctl restart php8.3-fpm(كيّفوا الفرع)، وsudo systemctl restart apache2إذا كنتم تستعملونmod_php. على RHEL أو AlmaLinux:sudo systemctl restart httpd. على cPanel مع PHP-FPM يعطيsystemctl list-units 'ea-php*'الاسم الدقيق للخدمة المطلوب إعادة تشغيلها.تحققوا من الإصدار الذي يُقدَّم فعليًا
سطر الأوامر ليس خدمة الويب. استعلموا من ملف FPM التنفيذي:
php-fpm8.3 -vعلى Debian وUbuntu، وphp-fpm -vعلى RHEL ومشتقاته، أو إصدار النطاق في cPanel. يجب أن يبلغ الرقم الحد الأدنى لفرعكم، أو أن يذكر سجله CVE-2026-91769. اختموا باستدعاء صادر تجريبي:php -r 'echo strlen(file_get_contents("https://your-domain.com/")), PHP_EOL;'.
إذا كان فرعكم منتهي الدعم (8.1 وما قبله)
بحسب HeroDevs، فإن فروع PHP من 5.6 إلى 8.1 منتهية الدعم ولا تتلقى إصلاحًا من المشروع لهاتين الثغرتين. لا تفترضوا شيئًا في أي اتجاه. ربما نقلت توزيعتكم الإصلاح إلى حزمتها: هذا ممكن وغير مضمون، ويُتحقق منه حزمة بحزمة عبر سجل التغييرات (apt changelog وrpm -q --changelog) وتتبّع الأمان الخاص بالتوزيعة. كما يقدّم ناشرون من أطراف ثالثة backports للإصدارات المهجورة.
في غياب إصلاح مؤكد لديكم ثلاث وسائل. الأولى الترحيل إلى فرع مدعوم، 8.3 أو 8.4 بعد اختبار موقعكم: الطريقة في قائمة التحقق الخاصة بترحيل PHP. الثانية حصر الاستدعاءات الصادرة من ذلك الكود في مضيفين تتحكمون في شهاداتهم. الثالثة تقييد حركة الخادم الصادرة في جدار الحماية. الأخيرتان تقلّلان التعرض ولا تصلحان شيئًا.
لا تضبطوا verify_peer_name على false أبدًا
أمام خطأ في الشهادة يغري الأمر بإضافة verify_peer_name => false في stream_context_create. هذا أسوأ من الثغرة: لم يعد يُتحقق من أي اسم مضيف، فتصلح أي شهادة معتمدة لأي مضيف. لا يذكر التنبيه أي حل مؤقت، وهذا الخيار ليس واحدًا منها. حين يفشل اتصال بعد التحديث، أصلحوا الشهادة.
إصلاح ثالث في OpenSSL خلال الربع نفسه
CVE-2026-14355 ثغرة مستقلة: تلف في الذاكرة داخل openssl_encrypt() مع الخوارزمية AES-WRAP-PAD (GH-22187). بحسب سجل تغييرات PHP (https://www.php.net/ChangeLog-8.php) فقد صُحّحت في PHP 8.4.23 بتاريخ 3 يوليو 2026 وفي PHP 8.5.8 بتاريخ 2 يوليو 2026. تمس التشفير لا التحقق من TLS: فلا تغيّر شيئًا في اختبار التعرض أعلاه.
إذا ثبّتم 8.4.26 أو 8.5.11 أو ما بعدهما فلديكم هذا الإصلاح أصلًا. أما الفرعان 8.2 و8.3 فلا نذكر لهما إصدارًا لأننا لم نتحقق منه: اقرؤوا سجل حزمتكم لمعرفة هل ترد فيه CVE-2026-14355.
حل المشكلات بعد التحديث
يشدّد الإصلاح فحصًا قائمًا. لذلك قد تفشل الآن بعض الاستدعاءات التي كانت تمر سابقًا، وهذه نتيجة متوقعة للإصلاح لا تراجعًا. الحالة التي تُختبر أولًا هي خدمة داخلية تأتي شهادتها من سلطة خاصة. هذه رسائل حقيقية قد تصادفونها مع العلاج المناسب.
الأخطاء المصادَفة وعلاجها
SSL operation failed with code 1ثمcertificate verify failed— الرسالة الكاملة المعتادة:stream_socket_client(): SSL operation failed with code 1. OpenSSL Error messages: error:0A000086:SSL routines::certificate verify failed. السبب المرجّح: الشهادة تعرض SAN من نوع DNS لا يتضمن المضيف المطلوب، بينما يتضمنه CN. كان الفحص القديم يقبلها بالعودة إلى CN، والجديد يرفضها. اقرؤوا الشهادة بـopenssl s_client -connect interne.your-domain.com:443 -servername interne.your-domain.com </dev/null 2>/dev/null | openssl x509 -noout -subject -ext subjectAltName. العلاج: إعادة إصدار الشهادة بـ SAN من نوع DNS صحيح لكل اسم مستعمل، وليس تعطيل التحقق أبدًا.file_get_contents(): Failed to enable crypto— تحذير يرافق الخطأ السابق. اقرؤوا الرسالة الكاملة التي تليه: بحسب الإصدار قد تجدون أيضًاPeer certificate CN=… did not match expected CN=…. السبب نفسه والعلاج نفسه.- شهادة بلا أي SAN، بـ CN فقط، تفشل مع ذلك — يُبقي الإصلاح العودة إلى CN للشهادات التي لا تحمل معرّف خدمة. فالسبب إذن في مكان آخر: سلطة لا يعتمدها العميل، أو مضيف مستدعى بكنية أو بعنوان IP غير موجود في الشهادة، أو شهادة منتهية الصلاحية. العلاج: إضافة السلطة الداخلية إلى
cafileفي سياق التدفق، وإعادة إصدار الشهادة بـ SAN. child exited on signal 11 (SIGSEGV)في سجل PHP-FPM — انهيار عامل أثناء استدعاء صادر عبر TLS يتوافق مع CVE-2026-91767. لا تستنتجوا من هذه القرينة وحدها: تحققوا من الإصدار وحدّثوا وانظروا هل يختفي النمط.php -vما زال يعرض الإصدار القديم — خدمة لم تُعد تشغيلها، أو سطر أوامر وFPM على فرعين مختلفين، أو صورة Docker أُعيد بناؤها دون--pull، أو إصدار النطاق لم يتغير في cPanel. ارجعوا إلى خطوة التحقق.- سجل التوزيعة لا يذكر الثغرة — غيابها لا يثبت أن الإصلاح موجود ولا أنه مفقود. راجعوا تتبّع الأمان الخاص بالتوزيعة، وإلا فقارنوا رقم المشروع بالحد الأدنى في الجدول.
تثبيت التحديث ضمن روتينكم
دوّنوا الحد الأدنى في جردكم
أضيفوا إلى جرد أسطولكم عمودًا باسم "الإصدار الأدنى" لكل فرع، بقيم الجدول. فيصبح أي إصدار دون الحد الأدنى ظاهرًا دون بحث.
خطّطوا لتحديثات PHP
الإصلاح الأمني في PHP تحديث ثانوي ضمن الفرع نفسه: خصّصوا نافذة منتظمة بدل ورشة عند كل تنبيه، مع إعادة تشغيل الخدمات والتحقق من الإصدار المُقدَّم.
اختبروا استدعاءً صادرًا بعد كل تحديث
أعيدوا
php -r 'echo strlen(file_get_contents("https://your-domain.com/")), PHP_EOL;'من كل خادم، واستدعاءً إلى خدماتكم الداخلية. يظهر خطأ الشهادة حينها فورًا، لا عند عميل.اربطوا هذا الإصلاح ببقية مراقبتكم
لطريقة جرد الأسطول اقرؤوا جرد إصدارات PHP لأسطول العملاء. وللثغرة الأخطر في الوقت الحالي انظروا PHP2Shell. ولتغيير إصدار موقع اتبعوا دليل محدد PHP في cPanel. ولفرع يوشك أن ينتهي عودوا إلى قائمة التحقق لترحيل PHP 8.2.