Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама
Новини 04 листопада 2026

Вразливість у Concurrency: вивід задачі міг призвести до виконання коду в Laravel

У Laravel 13.40.0 закрили вразливість у фасаді Concurrency, яка за певних умов давала віддалене виконання коду (RCE) без автентифікації. Драйвер process, що стоїть за замовчуванням, читав результат задачі з її stdout і робив unserialize() того, що там знаходив. Якщо задача друкувала хоч щось, на що впливає користувач, зловмисник міг підробити цей результат. Того ж дня вийшов і 12.71.0 з тим самим виправленням.

Це окрема від нещодавньої вразливості в TokenGuard проблема, і цього разу окремого попередження безпеки (GHSA) у laravel/framework на момент написання немає. Тож composer audit про неї не повідомить, а номерів CVE чи оцінки CVSS поки не існує.

Як працює драйвер process

Concurrency::run() запускає кожне замикання в окремому PHP-процесі через Artisan-команду invoke-serialized-closure. Дочірній процес виконує задачу, серіалізує повернене значення і пише в stdout JSON на кшталт {"successful": true, "result": "<serialize()>"}. Батьківський процес читає stdout, декодує JSON і викликає unserialize() поля result.

Слабке місце - stdout спільний. Усе, що задача виводить через echo, print, dump() чи сторонню бібліотеку, опиняється в тому ж потоці, що й результат. У березні, щоб виправити збій із zlib.output_compression (issue #59112), у PR #59224 додали обрізання виводу на першій парі байтів \x1f\x8b (початок gzip-потоку). Ця зміна вийшла в 12.55.0 і 13.0.0.

Як це перетворювалося на RCE

За описом виправлення, якщо задача друкує текст із запиту, зловмисник передає в параметрі готовий JSON із підробленим result, а за ним байти \x1f\x8b. Батьківський процес обрізає все після них, разом зі справжнім результатом, і десеріалізує підроблений. Для виконання команд вистачає ланцюжка гаджетів із самого фреймворку (PendingBroadcast -> Bus\Dispatcher -> system()), і тести в PR це демонструють.

Типові задачі, які могли таке друкувати: рядки прогресу, потоковий експорт, налагоджувальний вивід, повідомлення сторонніх пакетів. Окремо від атаки, будь-який вивід задачі ламав JSON, і запит падав з ErrorException: Trying to access array offset on null - той самий симптом, що й у #59112.

Кого це стосується

  • Драйвер process (значення default у config/concurrency.php, або CONCURRENCY_DRIVER=process) з Concurrency::run() - вразливий.
  • Concurrency::defer() результатів не читає: задачі запускаються у фоні, а їхній вивід ніхто не розбирає. Тести в PR окремо перевіряють, що відкладені задачі ключа не отримують. Проблема саме в run().
  • Драйвер fork працює через spatie/fork без розбору stdout і в межах веб-запиту взагалі недоступний. Виправлення його не чіпає.
  • Драйвер sync просто викликає замикання в тому самому процесі - серіалізації немає.

Найбільше ризикують задачі, що виконуються під час HTTP-запиту і виводять щось похідне від вхідних даних.

Що змінилося в 13.40.0

Обрізання за байтами \x1f\x8b прибрали повністю. Тепер:

  • для кожної задачі батьківський процес генерує випадковий 32-байтовий ключ і передає його дочірньому в змінній середовища LARAVEL_CONCURRENCY_HMAC_KEY; дочірній одразу прибирає її з середовища;
  • дочірній процес додає в кінець виводу рамку @@LARAVEL-CONCURRENCY-V1@@<base64>@@<hmac>@@ з HMAC-SHA256 на цьому ключі;
  • батьківський процес шукає рамки знизу вгору і бере лише ту, чий підпис збігся, а unserialize() виконує тільки для перевіреного вмісту.
$result = $this->parseEnvelope($result->output(), $envelopeKeys[$key]);

Опис PR згадує ключ застосунку, але в коді ключ саме випадковий для кожної задачі, а тест testEnvelopeSignedWithTheApplicationKeyIsRejected прямо перевіряє, що рамку, підписану APP_KEY, відхилено. Тож витік APP_KEY цей захист не обходить.

Вивід, у якому немає валідної рамки, тепер дає RuntimeException з першими 200 символами виводу, а не загадкову помилку про null. Повернені значення, як і раніше, десеріалізуються в будь-який тип, а винятки із задач приходять зі своїм класом.

Що зробити

Оновіть фреймворк:

composer update laravel/framework
composer show laravel/framework | grep versions

Потрібна версія не нижча за 13.40.0 або 12.71.0. Для 12.x GitHub-реліз окремо не оформили, але тег v12.71.0 з виправленням є і на Packagist.

Якщо оновитися одразу не виходить:

  • приберіть із задач Concurrency::run() будь-який вивід, де є дані користувача, включно з dump() і логуванням у stdout;
  • або тимчасово перемкніть драйвер на sync (CONCURRENCY_DRIVER=sync), пожертвувавши паралельністю.

І ще одна річ на час оновлення: якщо у ваших тестах Process::fake() повертав для invoke-serialized-closure голий JSON, після оновлення такі тести впадуть з RuntimeException. Самому фреймворку довелося переписати свій тест з таймаутом саме так.

Laravel 11 виправлення не отримав. Його код розбирає вивід інакше, без обрізання за \x1f\x8b, але спільний stdout і unserialize() там ті самі, а гілка вже не отримує оновлень безпеки. Якщо проєкт на 11.x використовує Concurrency::run(), діють ті самі тимчасові заходи, а план переходу на 12.x чи 13.x варто пришвидшити.

1

Читати в документації

Коментарі

Увійдіть, щоб залишити коментар

Будьте першим, хто залишить коментар!

Читайте також

Новини 04 листопада 2026

Laravel 13.40: довгі завдання черги, insertBefore() для middleware і strict для запиту

Laravel 13.40.0 додає Queue::whenJobRunsLongerThan() і Schedule::whenTaskRunsLongerThan() для завдань черги та планувальника, що виконуються задовго, а також insertBefore() і insertAfter() для вбудованого стеку middleware. Крім того - прапорець strict для $request->integer() і string() та DB::hasCommitId() для перевірки реплік.

Новини 04 листопада 2026

Synapse 0.3: дашборд для агентів на Laravel AI SDK навчився схвалювати інструменти

Synapse від Redberry - відкритий dev-дашборд для агентів на Laravel AI SDK: знаходить агентів у застосунку, дає говорити з ними в браузері й показує виклики інструментів, токени та міркування. У 0.3 додано схвалення інструментів, джерела, пояснення зупинок і інспектор кроків, а 0.3.1 виправляє запис розмов під Octane.

1

Вакансії за темою

King Group Нова
Сьогодні

Middle PHP developer

Middle PHP розробник для високонавантаженої веб-платформи Social Casino/Online Casino: розвиток продукту, перехід монолітного проєкту на мікросервіси (Symfony), оптимізація баз даних, написання unit та functional тестів. Стек: PHP 7.4, Symfony 4, Yii, PostgreSQL 14, Redis, RabbitMQ, NGINX. Вимоги: 3-4+ роки продуктового досвіду з PHP, Yii, Symfony, PostgreSQL, розуміння REST API, Git, ООП та SOLID. Досвід з брокерами повідомлень і DDD буде плюсом.

Tech Lead — Fintech

Tech Lead для фінтех-платформи бізнес-витрат і платежів: активна розробка, архітектурні рішення, стабільність продакшену та менторство команди. Ключовий стек: PHP, Laravel/Lumen, MySQL, Redis, Docker, знання JavaScript (Vue.js, React на базовому рівні). Вимоги: розуміння життєвого циклу карткових транзакцій і криптовалют, досвід побудови надійних фінансових систем (баланси, звірка, аудит, безпечні API), DevOps-навички на Linux.

Bewort Нова
Сьогодні

Senior Full-Stack Developer (PHP/Laravel, Vue)

Розробка та розвиток ключових функцій корпоративної платформи на Laravel з обробкою бекенду та фронтенду на Vue. Потрібні глибокі знання внутрішньої архітектури фреймворку, досвід застосування SOLID, DDD, подій і черг, а також досвід роботи зі складними проєктами. Обов'язкове активне використання AI-інструментів для написання коду та англійська не нижче B2. Переваги: досвід із Vue, мультитенантними SaaS, AWS, CI/CD та LLM-інтеграціями.

Пакети за темою

Kalimera

welldigit/kalimera

Interactive installer that scaffolds Laravel applications the Well Digit way.

v1.0.0 16

Bagisto

bagisto/bagisto

Bagisto — це платформа для електронної комерції, побудована на Laravel. Вона надає готове рішення для створення та управління інтернет-магазинами з підтримкою каталогу товарів, замовлень, платежів та клієнтів.

28,325 v2.5.0 13 28