تیم PHP روز چهارشنبه ۲۹ مهر ۱۴۰۵ (۲۱ اکتبر ۲۰۲۶) دو آسیب‌پذیری بحرانی را در خودِ PHP وصله کرد که به مهاجمِ بدون حساب کاربری اجازه می‌دهد روی سرور فرمان اجرا کند. اگر PHP شما 8.5.12، 8.4.27، 8.3.36 یا 8.2.35 نیست، یا بسته‌ای که از توزیع لینوکس گرفته‌اید هنوز به نسخه‌ی اصلاح‌شده‌ی توزیع نرسیده است، امروز ارتقا دهید، همه‌ی پردازه‌های PHP را دوباره راه‌اندازی کنید و لاگ‌ها را از ۲۵ مهر بررسی کنید. قاعده‌ی WAF و تنظیمات موقت فقط زمان می‌خرند.

مشکل در افزونه، قالب یا فریم‌ورک نیست؛ در بخشی از PHP است که هر درخواست وب را پیش از رسیدن به کد شما می‌خواند. پس وردپرس به‌روز، لاراول به‌روز یا کد امن به‌تنهایی کمکی نمی‌کند.

نکته: وضعیت این نوشته تا ۳۰ مهر ۱۴۰۵ بررسی شده است: تلاش برای حمله از چند منبع مستقل گزارش شده، اما نفوذ تأییدشده به یک سامانه‌ی واقعی هنوز گزارش نشده و این دو آسیب‌پذیری هنوز در فهرست آسیب‌پذیری‌های بهره‌برداری‌شده‌ی CISA (KEV) نیستند. هر تغییری در این وضعیت با تاریخ همین‌جا ثبت می‌شود.

در یک نگاه

موضوع وضعیت
چه چیزی دو آسیب‌پذیری در هسته‌ی پردازش درخواست PHP: CVE-2026-109618 (خرابی حافظه هنگام کمبود حافظه) و CVE-2026-109619 (وضعیت سراسری کهنه)
شدت امتیاز ۹٫۲ در CVSS 4.0، بحرانی، برای هر دو. عدد ۱۰ که روز اول دست‌به‌دست شد نادرست است
اثر اجرای فرمان روی سرور با کاربر وب‌سرور، بدون ورود؛ و نشت حافظه، از جمله رمز، توکن و کلید API درخواست‌های دیگر
بدترین چیدمان Apache با mod_php: حمله پیش از اجرای اولین خط کد اپلیکیشن رخ می‌دهد
نسخه‌های اصلاح‌شده 8.5.12، 8.4.27، 8.3.36 و 8.2.35
8.1 و قدیمی‌تر انتشار رسمی نمی‌گیرند؛ تیم PHP فقط وصله‌ی کد منبع برای 7.4، 8.0 و 8.1 منتشر کرده است
وضعیت حمله تلاش از ۲۵ مهر؛ کد اثبات مفهوم (PoC) عمومی است؛ نفوذ تأییدشده گزارش نشده
تنها راه کامل ارتقا به نسخه‌ی دقیق و راه‌اندازی دوباره‌ی همه‌ی پردازه‌های PHP

چه اتفاقی افتاد

ریشه‌ی ماجرا به ۱۴۰۳ برمی‌گردد. یکی از توسعه‌دهندگان PHP هنگام اصلاح یافته‌ای از ممیزی امنیتی Quarkslab نخستین نشانه‌های مشکلِ کمبود حافظه را دید، اما مسیر عملی‌ای برای سوءاستفاده پیدا نشد و اصلاح ماه‌ها معطل ماند. بنیاد PHP حالا این تأخیر را «شکستی ساختاری» می‌نامد. مرداد و شهریور ۱۴۰۵ سه تیم جداگانه، Calif، OpenAI و Wiz، در فاصله‌ی دو هفته مسیرهای عملی اجرای کد را گزارش کردند و اصلاح در اولویت اول قرار گرفت.

از ممیزی ۱۴۰۳ تا حمله پیش از وصله زمان‌ها به وقت تهران ۱۴۰۳ نخستین نشانه‌ها هنگام اصلاح یافته‌ای از ممیزی Quarkslab؛ اصلاح ماه‌ها معطل ماند ۲۰ مرداد ۱۴۰۵ Calif و OpenAI مسیر اجرای کد را گزارش می‌کنند؛ Wiz در ۲ شهریور ۲۵ مهر نخستین تلاش حمله در هانی‌پات‌های AWS، چهار روز پیش از وصله ۲۸ مهر، ۱۸:۳۰ شناسه‌های CVE با امتیاز نادرست ۱۰ نشت می‌کند ۲۸ مهر، ۲۳:۳۰ ویدیوی اثبات مفهوم به اشتباه منتشر می‌شود ۲۹ مهر، ۰۶:۳۲ قواعد WAF کلادفلر به‌طور پیش‌فرض فعال می‌شود ۲۹ مهر، ۱۷:۳۰ انتشار 8.5.12، 8.4.27، 8.3.36 و 8.2.35 ۲۹ و ۳۰ مهر تلاش‌های گسترده؛ نفوذ تأییدشده به سامانه‌ی واقعی گزارش نشده است
تلاش برای حمله چهار روز پیش از انتشار وصله شروع شد.

نمونه: زنجیره‌ی ۲۸ مهر. قرار بود وصله پنجشنبه ۳۰ مهر منتشر شود. سه‌شنبه ۲۸ مهر حدود ساعت ۱۸:۳۰ به وقت تهران، شناسه‌های CVE با امتیاز نادرست ۱۰ در شبکه‌های اجتماعی پخش شد؛ هنوز بدون جزئیات فنی. تیم PHP انتشار را یک روز جلو انداخت، چون توزیع‌های لینوکس هنوز مشغول بسته‌بندی بودند. همان شب یکی از تیم‌های پژوهشی ویدیوی اثبات مفهوم را به اشتباه منتشر کرد و نخستین مخزن‌های GitHub با ادعای کد حمله پیدا شدند. صبح چهارشنبه یک شرکت ایمیج‌های وصله‌شده را چند ساعت زودتر از موعد منتشر کرد. نسخه‌های اصلاح‌شده ساعت ۱۷:۳۰ همان روز به وقت تهران آمدند. پیش از همه‌ی این‌ها، AWS یک تلاش حمله را ۲۵ مهر در هانی‌پات‌هایش ثبت کرده بود و نمی‌داند مهاجم جزئیات را از کجا داشت.

امروز چه باید کرد

اگر فقط همین بخش را می‌خوانید، این جدول کافی است. ترتیبش مهم است: فهرست، وصله، راه‌اندازی دوباره، و بعد بررسی گذشته.

زمان کار مسئول
چند ساعت آینده فهرست همه‌ی سرویس‌هایی که PHP را به اینترنت نشان می‌دهند، از جمله کانتینرها، هاست‌های اشتراکی و سامانه‌هایی که فروشنده نصب کرده است مدیر فنی
همین امروز ارتقا به نسخه‌ی دقیق، یا بسته‌ی اصلاح‌شده‌ی توزیع، و راه‌اندازی دوباره‌ی کامل همه‌ی پردازه‌ها تیم عملیات
تا وصله نشده تنظیمات موقت همین نوشته، قاعده‌ی WAF در حالت مسدودسازی، و بستن دسترسی مستقیم به سرور اصلی عملیات و امنیت
تا ۷۲ ساعت بررسی لاگ‌ها و رفتار پردازه‌ها از ۲۵ مهر، نه از روز نصب وصله تیم امنیت
اگر سرور مدتی بی‌وصله در اینترنت بوده عوض کردن رمز پایگاه داده، کلیدهای API و توکن‌هایی که از این سرور عبور می‌کنند تیم امنیت
این هفته برنامه‌ی ارتقای سرویس‌های 8.1 و قدیمی‌تر، و 8.2 که ۱۰ دی ۱۴۰۵ از پشتیبانی خارج می‌شود مدیر فنی

این پرسش‌ها را از تیم فنی یا شرکت میزبانی بپرسید:

  1. روی هر سرویس اینترنتی کدام نسخه‌ی دقیق PHP اجرا می‌شود؟
  2. وصله را با نسخه‌ی بسته و اطلاعیه‌ی توزیع تأیید کرده‌اید، یا فقط با خروجی php -v؟
  3. پردازه‌های PHP-FPM یا Apache پس از نصب دوباره راه‌اندازی شدند؟
  4. لاگ‌ها از ۲۵ مهر بررسی شده‌اند، و چه چیزی دیده شد؟
  5. آیا سرور اصلی بدون عبور از CDN و WAF هم از اینترنت در دسترس است؟
  6. برای سرویس‌هایی که روی 8.1 یا قدیمی‌ترند چه برنامه‌ای داریم؟

نمونه: فروشگاه ووکامرسی روی هاست اشتراکی. شرکت میزبانی اطلاع داده است که «PHP همه‌ی سرویس‌ها به 8.2 یا بالاتر ارتقا یافت». این جمله به پرسش اصلی جواب نمی‌دهد: 8.4.26 هم بالاتر از 8.2 است و هنوز آسیب‌پذیر. سه پرسش اول فهرست بالا کار را روشن می‌کند. روی هاست اشتراکی از پشتیبانی بخواهید نسخه‌ی دقیق بسته‌ی PHP و اطلاعیه‌ای را که وصله را تأیید می‌کند نشانتان دهد، چون بعضی بسته‌های وصله‌شده‌ی کنترل‌پنل‌ها هنوز شماره‌ی قدیمی را نشان می‌دهند. اعلام اینکه «تابع‌های خطرناک غیرفعال شد» هم جای وصله را نمی‌گیرد: آسیب‌پذیری اول پیش از فراخوانی هر تابعی در کد شما رخ می‌دهد.

اگر فهرست کاملی از سرویس‌هایی که PHP را به اینترنت نشان می‌دهند ندارید، کار از همین‌جا شروع می‌شود؛ مدیریت سطح حمله برای همین دید بیرونی است.

چه کسی در معرض خطر است

هر سرویسی که درخواست وب را با PHP آسیب‌پذیر پاسخ می‌دهد. پژوهشگران Wiz روی ایمیج‌های رسمی وردپرس، دروپال و جوملا بدون احراز هویت اجرای کد گرفتند و می‌گویند حتی یک اپلیکیشن ساده‌ی «Hello World» روی نسخه‌ی آسیب‌پذیر می‌تواند در خطر باشد. Calif همین را در آزمایشگاه روی مجنتو، لاراول، سیمفونی، phpMyAdmin، Nextcloud و چند سامانه‌ی دیگر نشان داده است.

دامنه بزرگ است. طبق W3Techs در ۳۰ مهر ۱۴۰۵، PHP زبان سمت سرور ۶۹٫۳ درصد وب‌سایت‌هایی است که زبانشان معلوم است، و حدود ۴۸ درصد سایت‌های PHP روی 8.1 یا قدیمی‌تر کار می‌کنند که انتشار رسمی نمی‌گیرند. برای ایران آمار مستقلی پیدا نکردیم؛ برآوردی که یک فروشنده‌ی قالب وردپرس منتشر کرده، و روشش روشن نیست، سهم وردپرس را در سایت‌های ایرانی حدود نیمی می‌داند. بیشتر این سایت‌ها روی هاست اشتراکی‌اند، جایی که صاحب سایت خودش نمی‌تواند PHP را وصله کند.

خطر به چیدمان سرور بستگی دارد. جدول زیر خلاصه‌ی ارزیابی خودِ تیم PHP در دو اطلاعیه‌ی رسمی است:

چیدمان CVE-2026-109618 CVE-2026-109619
Apache با mod_php بیشترین خطر؛ اجرای کد پیش از کد اپلیکیشن اثبات شده اجرای کد اثبات شده
PHP-FPM (پشت Nginx یا Apache) در خطر؛ دو منبع رسمی PHP درباره‌ی اثبات کامل هم‌نظر نیستند مسیر session اثبات شده؛ به رفتار اپلیکیشن بستگی دارد
FrankenPHP احتمالاً آسیب‌پذیر؛ اثبات نشده در پیکربندی پیش‌فرض مسیری پیدا نشده، که به معنای مصون بودن نیست
LiteSpeed (LSAPI) احتمالی؛ اثبات نشده مشروط
php-cgi در فهرست رسمی؛ تحلیل جداگانه منتشر نشده در فهرست رسمی
خط فرمان (CLI) خارج از دامنه خارج از دامنه

درباره‌ی FPM دقیق باشیم: اطلاعیه‌ی رسمی آسیب‌پذیری اول می‌گوید اجرای کامل کد روی FPM نشان داده نشده و آسیب‌پذیری آن فقط از روی کد منبع برآورد شده است، اما بنیاد PHP می‌گوید اجرای کد روی FPM هم از راه مسیرهای وابسته به اپلیکیشن تأیید شده است. نتیجه برای شما یکی است: Nginx با FPM هم باید وصله شود.

نمونه. نصب معمول Apache و PHP روی Debian و Ubuntu، با بسته‌ی libapache2-mod-php، همان mod_php است؛ یعنی پرخطرترین چیدمان، حتی اگر php-fpm هم نصب باشد و کاری انجام ندهد. در مقابل، Apache که درخواست را با ماژول proxy_fcgi به PHP-FPM می‌دهد چیدمان FPM است. برای فهمیدنش ببینید کدام ماژول در Apache بار شده است؛ دستورش در بخش وصله آمده.

آسیب‌پذیری اول: کمبود حافظه در لحظه‌ی بد (CVE-2026-109618)

به زبان ساده. PHP برای هر درخواست سقف حافظه دارد و درخواستی را که از سقف بگذرد همان‌جا متوقف می‌کند. اشکال این است که توقف ممکن است وسط پر کردن دفترِ داخلی PHP رخ دهد؛ مثل انبارداری که در دفتر می‌نویسد «سه جعبه رسید» و پیش از گذاشتن جعبه‌ی سوم در قفسه صدایش می‌کنند. نیروی نظافت بعداً به دفتر اعتماد می‌کند و سراغ جعبه‌ای می‌رود که هرگز آن‌جا نبوده است. مهاجم درخواست را طوری می‌سازد که حافظه درست در همین لحظه تمام شود و پاک‌سازی روی داده‌ای کار کند که او شکلش را تعیین کرده است.

برای متخصص. PHP در نسخه‌های آسیب‌پذیر هنگام شکست تخصیص حافظه با longjmp() از وضعیت جاری بیرون می‌پرد. در بعضی مسیرها حافظه‌ی درخواست پیش از مقداردهی کامل در دسترس است و پاک‌سازی پایان درخواست همان حافظه‌ی نیمه‌کاره را می‌خواند. اطلاعیه‌ی رسمی سه نکته دارد که در بیشتر گزارش‌های فارسی نیامده است:

  • هر شکست تخصیص حافظه می‌تواند ماشه باشد، نه فقط رسیدن به memory_limit؛ و تخصیصی که شکست می‌خورد لازم نیست به حافظه‌ی آسیب‌دیده ربطی داشته باشد.
  • ساختاری که خراب می‌شود جدول متغیرهای درخواست است، مثل $_POST، که PHP هنگام خواندن بدنه‌ی درخواست می‌سازد؛ نه ساختارهای session.
  • روی mod_php پاک‌سازی حتی وقتی شروع درخواست شکست خورده اجرا می‌شود؛ یعنی همه‌ی این ماجرا پیش از اجرای کد اپلیکیشن است و صفحه‌ی ورود یا کد امن جلویش را نمی‌گیرد.

Datadog و Calif محل دقیق را در تابعی از موتور Zend نشان داده‌اند که شمارنده‌های جدول را پیش از تخصیص کلید جدید بالا می‌برد؛ اگر آن تخصیص شکست بخورد، خانه‌ای شمرده شده که هرگز پر نشده است. وصله سازوکار longjmp() را برای کمبود حافظه حذف کرده است: PHP حالا در نقطه‌ی امن بعدی متوقف می‌شود و در آستانه‌ی بالاتر پردازه را فوراً می‌بندد.

حمله پیش از کد شما اجرا می‌شود CVE-2026-109618 روی Apache با mod_php پیش از اجرای کد اپلیکیشن ۱. درخواست فرم ساختگی، بدون ورود ۲. PHP بدنه را در جدول ‎$_POST می‌چیند ۳. تخصیص حافظه وسط کار شکست می‌خورد و PHP بیرون می‌پرد ۴. پاک‌سازی، خانه‌ی نیمه‌کاره را معتبر می‌داند ۵. فرمان با کاربر www-data اجرا می‌شود؛ پاسخ می‌تواند 200 باشد WAF: سقف اندازه و تعداد فیلدها، فقط تا حدی post_max_size پایین: خطر را کم می‌کند وصله: علت را برمی‌دارد EDR: پوسته‌ای که PHP باز می‌کند را می‌بیند
فقط وصله علت را برمی‌دارد؛ بقیه‌ی کنترل‌ها خطر را کم می‌کنند یا حمله را می‌بینند.

نمونه: پاسخ ۲۰۰ همیشه یعنی بی‌خطر نیست. در آزمایشگاه Datadog یک فرم معمولی، نه آپلود فایل، با یک نام فیلد تودرتو و بسیار بلند (حدود ۳٫۵ مگابایت) فرستاده شد. پاسخ پس از حدود سه ثانیه با کد HTTP 200 برگشت و متن خطای کمبود حافظه در بدنه‌اش بود. در همین درخواست فرمانی با کاربر www-data اجرا شد و پردازه زنده ماند. تلاش‌های ناموفق معمولاً با خطای ۵۰۰ و خرابی پردازه دیده می‌شوند؛ تلاش موفق ممکن است هیچ‌کدام را نداشته باشد. به همین دلیل بستن فقط درخواست‌های multipart کافی نیست.

آسیب‌پذیری دوم: اشاره‌گری که از درخواست قبلی جا می‌ماند (CVE-2026-109619)

به زبان ساده. هر پردازه‌ی PHP درخواست‌های زیادی را پشت سر هم پاسخ می‌دهد، مثل اتاق هتلی که میان دو مهمان نظافت می‌شود. در این آسیب‌پذیری وقتی مهمان قبلی ناگهانی می‌رود، با خطا یا پایان مهلت، بخشی از نظافت انجام نمی‌شود. یادداشتی می‌ماند که می‌گوید «وسایل شما در کشوی سوم است»، در حالی که کشوی سوم حالا به کس دیگری داده شده است. درخواست بعدی به همان یادداشت عمل می‌کند. اگر مهاجم هر دو درخواست را بفرستد و هر دو به یک پردازه برسند، می‌تواند تعیین کند در آن کشو چه باشد.

برای متخصص. PHP بخشی از وضعیت هر پردازه را سراسری نگه می‌دارد: وضعیت خطا، session، اشیا و افزونه‌ها. این وضعیت موقتاً به حافظه‌ی درخواست جاری اشاره می‌کند. اطلاعیه‌ی رسمی می‌گوید اگر درخواستی ناگهانی قطع شود، با خطای تجزیه، خطای مهارنشده، require ناموفق، پایان مهلت اجرا یا کمبود حافظه، یا اگر هشداری دیرهنگام هنگام پاک‌سازی این وضعیت را دوباره پر کند، اشاره‌گر پس از آزاد شدن حافظه باقی می‌ماند. درخواست بعدی روی همان پردازه ممکن است پیش از مقداردهی کامل آن را بخواند. دو مسیر اثبات شده است:

  • backtrace خطای مهلک در PHP 8.5. تنظیم fatal_error_backtraces از 8.5 اضافه شده و پیش‌فرضش روشن است. این مسیر پایه‌ی اجرای کد اثبات‌شده روی mod_php است و Wiz با آن روی دروپال اجرای کد گرفت.
  • پیشرفت آپلود session. این قابلیت به‌طور پیش‌فرض روشن است، هم روی mod_php و هم روی FPM اثبات شده، و لازم نیست اپلیکیشن اصلاً session_start() را صدا بزند.

تیم PHP صریحاً می‌گوید تغییر error_reporting، استفاده از @ یا خاموش کردن display_errors و log_errors محافظتی نمی‌دهد. تعداد بیشتر پردازه‌ها احتمال موفقیت هر تلاش را کم می‌کند، اما شرط آسیب‌پذیری را از میان نمی‌برد. Wiz مسیر دیگری هم در OPcache گزارش کرده که در اطلاعیه‌های رسمی PHP نیامده است.

یک اشاره‌گر کهنه، از یک درخواست به درخواست بعدی CVE-2026-109619 یک پردازه‌ی PHP، دو درخواست پشت سر هم درخواست الف (مهاجم) خطای مهلک، پایان مهلت یا کمبود حافظه وضعیت سراسری هنوز به حافظه‌ی الف اشاره می‌کند حافظه آزاد شد، اشاره‌گر ماند درخواست ب (مهاجم) روی همان پردازه پیشرفت آپلود، هشدار INI یا backtrace در 8.5 نشت حافظه در کوکی PHPSESSID پاسخ، یا اجرای کد وصله: وضعیت پیش از استفاده‌ی دوباره پاک می‌شود session.upload_progress.enabled=0 fatal_error_backtraces=0 (فقط 8.5) pm.max_requests=1 (پرهزینه)
دو آسیب‌پذیری زنجیره می‌شوند: کمبود حافظه‌ی آسیب‌پذیری اول یکی از راه‌های ساختن وضعیت کهنه است.

نمونه: کوکی‌ای که سایت هرگز نساخته است. سایتی که اصلاً از session استفاده نمی‌کند ناگهان در پاسخ یک کوکی PHPSESSID بسیار بلند و درهم می‌فرستد. طبق تحلیل Wiz، این همان حافظه‌ی بازیافته‌ی پردازه است که به سمت مهاجم برمی‌گردد و می‌تواند رمز، توکن احراز هویت، کلید API یا گواهی درخواست‌های دیگر را در خود داشته باشد. این نشت به اجرای کد نیازی ندارد؛ پس سروری که مدتی بی‌وصله در اینترنت بوده ممکن است رازهایش را از دست داده باشد، حتی اگر کسی رویش فرمانی اجرا نکرده باشد.

وصله‌ی درست، و تله‌ی شماره‌ی نسخه

نسخه‌های اصلاح‌شده 8.5.12، 8.4.27، 8.3.36 و 8.2.35 هستند. هر نسخه‌ی پایین‌تر در همان شاخه آسیب‌پذیر است. اما بیشتر سرورها PHP را از php.net نمی‌گیرند؛ از مخزن توزیع لینوکس یا کنترل‌پنل می‌گیرند، و این‌ها وصله را بدون تغییر شماره‌ی نسخه منتقل می‌کنند.

آیا واقعاً وصله شده‌ایم؟ PHP کجا به درخواست وب پاسخ می‌دهد؟ سرورها، کانتینرها، کنترل‌پنل‌ها این PHP از کجا آمده؟ php.net یا ایمیج رسمی Docker دست‌کم 8.5.12، 8.4.27، 8.3.36 یا 8.2.35؟ بسته‌ی توزیع لینوکس یا کنترل‌پنل نسخه‌ی بسته به نسخه‌ی اصلاح‌شده‌ی توزیع رسیده؟ طبق اطلاعیه‌ی توزیع یا changelog؛ php -v ملاک نیست 8.1 یا قدیمی‌تر انتشاری نمی‌آید: وصله‌ی منبع یا فروشنده‌ی LTS، و برنامه‌ی ارتقا نه همین امروز وصله کنید؛ تا آن زمان تنظیمات موقت و WAF در حالت مسدودسازی بله پردازه‌ها بعد از نصب دوباره راه‌اندازی شدند؟ لاگ‌ها را از ۲۵ مهر بررسی کنید اگر مدتی بی‌وصله در اینترنت بوده: رمزها و کلیدها را عوض کنید
برای PHP توزیع یا کنترل‌پنل، نسخه‌ی بسته تصمیم می‌گیرد، نه php -v.
منبع PHP بسته‌ی وصله‌شده آنچه php -v نشان می‌دهد
php.net و ایمیج رسمی Docker 8.5.12، 8.4.27، 8.3.36، 8.2.35 همان عدد
Ubuntu 24.04 8.3.6-0ubuntu0.24.04.13 8.3.6
Ubuntu 22.04 8.1.2-1ubuntu2.28 8.1.2
Debian 12 8.2.35-1~deb12u1 8.2.35
Debian 13 8.4.27-1~deb13u1 8.4.27
AlmaLinux 9 (ماژول php:8.3) 8.3.36، یا بسته‌ی میانی 8.3.33-1 (alma.1) 8.3.36 یا 8.3.33
cPanel، DirectAdmin و Plesk بسته‌ی وصله‌شده‌ی کنترل‌پنل گاهی همان عدد قبلی؛ changelog را ببینید

این شماره‌ها از اطلاعیه‌های Ubuntu، Debian و AlmaLinux تا ۳۰ مهر است. Red Hat تا این تاریخ همه‌ی شاخه‌ها را وصله نکرده بود؛ اطلاعیه‌ی RHSB-2026-013 را دنبال کنید. مخزن داوطلبانه‌ی remirepo هم روز انتشار به‌روز نشد و تیم PHP توصیه کرد به بسته‌ی توزیع یا ساخت از منبع برگردید.

قاعده ساده است: برای PHP توزیع یا کنترل‌پنل، نسخه‌ی بسته را با اطلاعیه‌ی امنیتی همان توزیع مقایسه کنید. changelog معمولاً هر دو شناسه را دارد و تأیید دوم است، اما همیشه نه: در آزمون ما روی AlmaLinux 9، بسته‌ی وصله‌شده‌ی 8.3.36 در changelog فقط نوشته بود «rebase to 8.3.36» و شناسه‌ای نداشت. در ایمیج‌های slim کانتینر هم changelog اصلاً حذف شده است.

برای پیدا کردن PHP‌ای که واقعاً به وب پاسخ می‌دهد، نه نسخه‌ی خط فرمان:

# Which processes serve PHP
ps -eo user,pid,args | grep -E '[p]hp-fpm|[a]pache2|[h]ttpd'

# Apache: built-in PHP (php_module) or FPM through proxy_fcgi? (RHEL family: httpd -M)
apache2ctl -M 2>/dev/null | grep -Ei 'php|proxy_fcgi'

# Debian / Ubuntu: compare the package version with your distribution's advisory
dpkg-query -W 'php*-fpm' 'php*-cli' 'libapache2-mod-php*'
zgrep -E 'CVE-2026-10961[89]' /usr/share/doc/php8.3-fpm/changelog.Debian.gz

# RHEL, AlmaLinux, Rocky, cPanel ea-php: the version first; a rebased package's
# changelog may only say "rebase to 8.3.36" and name no CVE
rpm -q php-fpm
rpm -q --changelog php-fpm | grep -E 'CVE-2026-10961[89]'

# After the restart, no process may still run a replaced PHP file (expect no output)
grep -lE '(php|libphp).*\(deleted\)' /proc/[0-9]*/maps 2>/dev/null

# Containers: the official php image reports the real upstream version
docker ps --format '{{.Names}}  {{.Image}}'

پس از نصب، همه‌ی پردازه‌ها را کامل دوباره راه‌اندازی کنید، نه فقط reload؛ پردازه‌ای که پیش از نصب شروع شده همچنان کد قدیمی را اجرا می‌کند. روی Debian و Ubuntu دستورش systemctl restart php8.3-fpm apache2 است و روی خانواده‌ی RHEL systemctl restart php-fpm httpd. اگر Apache با mod_php کار می‌کند، راه‌اندازی دوباره‌ی php-fpm به‌تنهایی سایت را وصله نمی‌کند. دستور آخرِ بلوک بالا پس از راه‌اندازی دوباره نباید چیزی نشان دهد. برای کانتینرها برچسب جدید کافی نیست: ایمیج را دوباره بگیرید و سرویس را دوباره مستقر کنید. ایمیج‌های رسمی Docker برای 8.1 و قدیمی‌تر برچسب وصله‌شده ندارند.

نمونه: سروری که 8.3.6 نشان می‌دهد. این را در یک کانتینر تمیز Ubuntu 24.04 آزمودیم. php -v عدد 8.3.6 را نشان می‌دهد که از 8.3.36 خیلی پایین‌تر به نظر می‌رسد. dpkg-query نسخه‌ی بسته را 8.3.6-0ubuntu0.24.04.13 نشان می‌دهد، همان نسخه‌ای که اطلاعیه‌ی Ubuntu اصلاح‌شده می‌داند، و changelog هر دو شناسه را دارد؛ پس بسته وصله شده است. اما تا Apache و php-fpm دوباره راه‌اندازی نشده بودند، دستور آخر بلوک بالا هر دو پردازه‌ی apache2 و php-fpm8.3 را نشان می‌داد، یعنی هنوز کد قدیمی در حافظه بود. پس از راه‌اندازی دوباره، خروجی خالی شد.

اگر سرورتان مستقیم به مخزن‌های بسته یا GitHub دسترسی ندارد، که در ماه‌های اخیر برای بعضی مراکز داده‌ی داخلی پیش آمده است، آینه‌ی داخلی یا راه انتقال بسته را از پیش آماده کنید. وصله‌ی اضطراری بعدی هم منتظر نمی‌ماند.

اگر امروز نمی‌توانید وصله کنید

تیم PHP صریح است: این تنظیمات بعضی مسیرهای حمله را می‌بندند، اما نصب را امن نمی‌کنند، و هیچ تنظیم عمومی‌ای هر دو آسیب‌پذیری را کامل نمی‌بندد. هر تنظیم باید در php.ini‌ای که وب‌سرور می‌خواند، در pool مربوط به FPM یا در پیکربندی سرور اعمال شود و پس از آن همه‌ی پردازه‌ها دوباره راه‌اندازی شوند. ini_set() و فایل .user.ini دیر عمل می‌کنند. روی Debian و Ubuntu، FPM فایل /etc/php/8.3/fpm/php.ini را می‌خواند و PHPِ درون Apache فایل /etc/php/8.3/apache2/php.ini را، و php -i فقط فایل خط فرمان را نشان می‌دهد.

تنظیم برای چه چیزی را می‌بندد چه چیزی را نمی‌بندد هزینه
session.upload_progress.enabled = 0 CVE-2026-109619 مسیرهای اثبات‌شده‌ی session گونه‌های دیگر نوار پیشرفت آپلود کار نمی‌کند
fatal_error_backtraces = 0 (فقط 8.5) CVE-2026-109619 مسیر backtrace مسیرهای دیگر اطلاعات اشکال‌زدایی کمتر
post_max_size پایین: ۸ مگابایت بدون آپلود، ۳۲ با آپلود CVE-2026-109618 بخشی از مسیرهای بدنه‌ی درخواست مسیرهای دیگر کمبود حافظه آپلودهای بزرگ رد می‌شوند
memory_limit = -1 با php_admin_value CVE-2026-109618 راهکار اصلی پیکربندی از نظر PHP شکست تخصیص‌های دیگر فقط همراه سقف حافظه‌ی cgroup یا کانتینر برای هر پردازه
سقف در لایه‌ی جلویی: اندازه‌ی بدنه، تعداد فیلدها و بخش‌ها، طول نام، عمق تودرتو CVE-2026-109618 بخشی از درخواست‌های ساختگی ورودی‌های تغییرشکل‌یافته ممکن است درخواست سالم رد شود
pm.max_requests = 1 CVE-2026-109619 شرط «همان پردازه» کاهش جدی کارایی
; the php.ini the web server loads (fpm/ or apache2/, not cli/), then restart
session.upload_progress.enabled = 0
; PHP 8.5 only
fatal_error_backtraces = 0
; 8M without uploads, 32M with uploads; keep upload_max_filesize below it
post_max_size = 8M
upload_max_filesize = 4M

نکته: برای محدود کردن حافظه هرگز از RLIMIT_AS یا RLIMIT_DATA استفاده نکنید. تیم PHP هشدار داده که این دو دقیقاً همان شکست تخصیصی را می‌سازند که آسیب‌پذیری اول را فعال می‌کند. سقف حافظه را با cgroup یا تنظیمات کانتینر بگذارید، طوری که فقط همان پردازه بسته شود.

نمونه: فروشگاهی که فایل نمی‌گیرد. فروشگاهی که در فرم‌هایش آپلود فایل ندارد post_max_size را روی ۸ مگابایت و session.upload_progress.enabled را روی صفر می‌گذارد، multipart را در لایه‌ی جلویی می‌بندد، php-fpm را دوباره راه‌اندازی می‌کند و همان شب وصله را نصب می‌کند. این سه تنظیم چند ساعت فرصت می‌دهند، نه بیشتر.

WAF: لایه‌ی کمکی، نه وصله

چند ارائه‌دهنده قاعده‌ی اختصاصی منتشر کرده‌اند: کلادفلر قاعده‌ها را از صبح ۲۹ مهر برای طرح‌های رایگان و پولی به‌طور پیش‌فرض فعال کرد و درخواست و پاسخ را با هم بررسی می‌کند، Akamai قاعده‌ی 3000991 را منتشر کرد، و Imperva، Sucuri و Imunify360 هم وصله‌ی مجازی دادند. AWS قاعده‌ی مدیریت‌شده‌ی اختصاصی ندارد و فقط راهنمای قاعده‌ی سفارشی منتشر کرده است. کلادفلر همچنین گزارش داده که مهاجمان ورودی را تغییر می‌دهند تا از قاعده رد شوند.

از ارائه‌دهنده‌های داخلی CDN و WAF قاعده‌ی منتشرشده‌ای برای این دو آسیب‌پذیری پیدا نکردیم. اگر سایتتان پشت یکی از آن‌هاست، بپرسید آیا قاعده‌ای برای هر دو CVE فعال است و در حالت مسدودسازی کار می‌کند، و مطمئن شوید سرور اصلی بدون عبور از CDN در دسترس نیست. برای سنجیدن اینکه WAF واقعاً چه چیزی را می‌گیرد، اثربخشی WAF را کلاس‌به‌کلاس بسنجید.

نمونه: محدودیت بازرسی بدنه. AWS WAF بسته به سرویس فقط ۸ تا ۶۴ کیلوبایت اول بدنه را بازرسی می‌کند. نام فیلد چندمگابایتی آزمایشگاه Datadog از این محدوده بسیار بیرون است؛ اگر رفتار با درخواست‌های بزرگ‌تر از سقف روی «مسدود کن» تنظیم نشده باشد، WAF اصلاً بخش خطرناک را نمی‌بیند.

آیا به ما حمله شده است؟

AWS توصیه می‌کند بررسی را دست‌کم از ۲۵ مهر شروع کنید، نه از روز نصب وصله. یک امضای واحد وجود ندارد و این حمله‌ها ردپای کمی می‌گذارند؛ پس دنبال رفتار بگردید، نه کد وضعیت HTTP.

منبع داده دنبال چه بگردید
لاگ خطای PHP خطای کمبود حافظه با «in Unknown on line 0»، یعنی پیش از اجرای هر اسکریپتی
لاگ خطای Apache خرابی پردازه‌ی فرزند (کد AH00052 با Segmentation fault) پس از POSTهای غیرعادی
لاگ PHP-FPM پردازه‌هایی که با سیگنال ۱۱ (SIGSEGV) بسته شده‌اند، یا راه‌اندازی دوباره‌ی پیاپی
لاگ دسترسی و WAF POST با بدنه‌ی بسیار بزرگ، نام فیلد بسیار بلند، بخش‌های multipart زیاد، یا فیلد PHP_SESSION_UPLOAD_PROGRESS
پاسخ‌های HTTP کوکی PHPSESSID بسیار بلند یا درهم در پاسخ
پایش پردازه و EDR پوسته‌ای که پردازه‌ی php-fpm یا Apache باز می‌کند و به بیرون وصل می‌شود
پایش فایل فایل PHP تازه در پوشه‌های قابل نوشتن، cron یا حساب کاربری تازه

نمونه: دو خطی که کنار هم معنا دارند. این دو خط، که ساختگی‌اند ولی قالبشان همان قالب واقعی لاگ است، اگر در لاگ یک سرور Apache با mod_php به فاصله‌ی چند ثانیه دیده شوند ارزش بررسی دارند:

PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 3670048 bytes) in Unknown on line 0
[core:notice] [pid 812] AH00052: child pid 4127 exit signal Segmentation fault (11)

«Unknown on line 0» یعنی حافظه پیش از اجرای هر اسکریپتی تمام شده است. هیچ‌کدام از این نشانه‌ها به‌تنهایی تشخیص قطعی نیست و نبودشان هم سلامت سرور را ثابت نمی‌کند. فهرست نشانی‌های IP که AWS منتشر کرده شامل زیرساخت ناشناس‌سازی مشترک است؛ خودِ AWS می‌گوید آن‌ها را بررسی کنید، نه مسدود.

اگر چیزی پیدا کردید، پیش از هر تغییری لاگ‌ها، تنظیمات و فایل‌های مشکوک را نگه دارید، سرور را جدا کنید، رمزها و کلیدهایی را که از آن عبور می‌کنند عوض کنید و سرور را از نو بسازید.

وصله‌های سه ماه اخیر که همراهش می‌آیند

نسخه‌های ۲۹ مهر همه‌ی اصلاح‌های قبلی همان شاخه را هم دارند. سه انتشار امنیتی قبلی، ۱۱ و ۱۲ تیر، ۸ مرداد و ۲ مهر، روی هم ۱۷ اطلاعیه داشتند که بیشتر گزارش‌ها از آن‌ها نگذشتند. مهم‌ترین‌ها برای وب‌سایت‌های معمول:

انتشار شناسه شدت بخش اثر
۲ مهر CVE-2026-91765 بالا سرور SOAP از کار انداختن سرویس با درخواست SOAP بسیار تودرتو، بدون احراز هویت
۲ مهر CVE-2026-91766 متوسط پوشش‌دهنده‌ی http:// ارسال سرآیندهای Authorization، Cookie و Proxy-Authorization به مقصد تغییرمسیر در دامنه‌ی دیگر
۲ مهر CVE-2026-91768 متوسط PHP-FPM دور زدن فهرست مجاز IPv6
۲ مهر CVE-2026-91769 متوسط OpenSSL در PHP پذیرفتن نام گواهی از CN پس از عدم تطابق SAN
۸ مرداد CVE-2026-17543 بالا افزونه‌ی pgsql تزریق SQL در pg_insert، pg_update، pg_select و pg_delete
۸ مرداد CVE-2026-17544 بالا bcmath نوشتن بیرون از محدوده در bccomp()، فقط 8.4 و 8.5

نمونه: یک نشانی مجاز که یک بازه شد. در CVE-2026-91768، PHP-FPM برای بررسی listen.allowed_clients فقط ۱۲ بایت از ۱۶ بایت نشانی IPv6 را مقایسه می‌کرد. پس هر نشانی مجاز عملاً یک بازه‌ی /96 بود و هر ماشینی در آن بازه می‌توانست مستقیم با FPM صحبت کند.

این اصلاح‌ها فقط به شاخه‌های پشتیبانی‌شده رسیده‌اند. آخرین انتشار 8.1 نسخه‌ی 8.1.34 در ۲۷ آذر ۱۴۰۴ بوده است.

این ماجرا درباره‌ی مهلت وصله چه می‌گوید

این بخش برداشت ماست. ضعفی که از ۱۴۰۳ نیمه‌شناخته بود، در مرداد و شهریور ۱۴۰۵، در فاصله‌ی دو هفته، به دست سه تیم مستقل به اجرای کد رسید. Wiz نوشته که در یافتن آسیب‌پذیری و ساختن زنجیره‌ی حمله از مدل‌های هوش مصنوعی کمک گرفته است؛ بنیاد PHP هم می‌گوید هوش مصنوعی به اعتبارسنجی و دسته‌بندی گزارش‌ها کمک می‌کند و تصمیم با انسان است. پس از نشت شناسه‌ها، مخزن‌هایی با ادعای کد حمله در چند ساعت پیدا شدند؛ هرچند تیم PHP تا لحظه‌ی انتشار هیچ‌کدام را کارا نیافت.

نتیجه برای مدیر روشن است: برای سرویس‌های اینترنتی، مهلت ۳۰ روزه‌ی وصله‌ی بحرانی دیگر واقع‌بینانه نیست. چیزی که در چنین روزی واقعاً به کار می‌آید از پیش ساخته می‌شود: فهرست به‌روز سرویس‌ها، راه نصب وصله حتی وقتی مخزن‌های خارجی در دسترس نیستند، و لاگی که بشود از چند روز پیش بررسی‌اش کرد.

پرسش‌های رایج

وردپرس یا لاراول ما به‌روز است؛ باز هم در خطریم؟ بله، اگر خودِ PHP وصله نشده باشد. مشکل در PHP است و به‌روزرسانی CMS یا فریم‌ورک آن را برطرف نمی‌کند.

سایت پشت CDN و WAF است؛ همین کافی نیست؟ نه. مهاجمان ورودی را تغییر می‌دهند تا از قاعده رد شوند، بعضی WAFها فقط ابتدای بدنه را می‌بینند، و سرور اصلی گاهی بدون عبور از WAF هم در دسترس است. WAF را لایه‌ی کمکی بدانید و وصله را کنترل اصلی.

php -v نسخه‌ی 8.3.6 نشان می‌دهد؛ یعنی آسیب‌پذیریم؟ نه لزوماً. Ubuntu وصله را بدون تغییر شماره‌ی نسخه منتقل کرده است. نسخه‌ی بسته را با اطلاعیه‌ی امنیتی توزیعتان مقایسه کنید و مطمئن شوید پردازه‌ها پس از نصب کامل دوباره راه‌اندازی شده‌اند.

هنوز PHP 7.4 یا 8.1 داریم؛ چه کنیم؟ انتشار رسمی نمی‌آید. وصله‌ی کد منبعی را که تیم PHP برای 7.4، 8.0 و 8.1 منتشر کرده اعمال کنید یا از فروشنده‌ی پشتیبانی بلندمدت بگیرید؛ تا آن زمان تنظیمات موقت و جداسازی سرور را به کار ببرید و برنامه‌ی ارتقا را همین هفته بنویسید.

هاست اشتراکی داریم و به سرور دسترسی نداریم؛ چه کاری از ما برمی‌آید؟ از شرکت میزبانی نسخه‌ی دقیق PHP، تاریخ راه‌اندازی دوباره‌ی پردازه‌ها و نتیجه‌ی بررسی لاگ‌ها از ۲۵ مهر را بخواهید. «8.2 یا بالاتر» جواب این پرسش‌ها نیست.

منابع