---
title: "ReDoS у Symfony HttpFoundation і XXE у PhpSpreadsheet: що оновити в Laravel-проєкті"
url: https://laravelukraine.com/blog/redos-u-symfony-httpfoundation-i-xxe-u-phpspreadsheet-shho-onoviti-v-laravel-projekti
date: 2026-10-28
---

# ReDoS у Symfony HttpFoundation і XXE у PhpSpreadsheet: що оновити в Laravel-проєкті

27 жовтня GitHub Advisory Database додала дві групи попереджень, які прямо стосуються Laravel-проєктів. Перше - [ReDoS у `symfony/http-foundation`](https://github.com/advisories/GHSA-r925-mgvr-h9cc) (CVE-2026-108082): один неавтентифікований HTTP-запит із підготовленим заголовком `Cache-Control` займає процес майже на секунду. Друге - кілька вразливостей у PhpSpreadsheet, бібліотеці, на якій тримається Laravel Excel.

Обидва пакети ви, найімовірніше, не ставили напряму, тож у `composer.json` їх не видно. Саме тому такі попередження легко пропустити.

### ReDoS у HttpFoundation: чому вразливий кожен Laravel-застосунок

`Illuminate\Http\Request` успадковує `Symfony\Component\HttpFoundation\Request`, а `HeaderBag` під час створення кожного запиту розбирає заголовок `Cache-Control` через `HeaderUtils::split()`. Регулярний вираз у цьому методі дозволяв ряду пробілів перед роздільником «розподілятися» між ітераціями зовнішнього повторення експоненційною кількістю способів, і рушій PCRE перебирав їх усі.

Цифри з [попередження Symfony](https://symfony.com/blog/cve-2026-108082-redos-in-headerutils-split-reachable-through-the-cache-control-request-header): 17 пробілів у заголовку на 8 КБ коштують 813 мс CPU на PHP 8.5, і кожен додатковий пробіл подвоює час. Від 18 пробілів `preg_match_all()` упирається в `pcre.backtrack_limit` і здається, а `split()` повертає порожній масив, тобто всі директиви заголовка мовчки зникають.

На практиці це дешевий DoS: щоб зайняти всі воркери PHP-FPM, вистачить кількох десятків паралельних запитів, і для цього не потрібні ні обліковий запис, ні конкретний маршрут. Заголовок розбирається до роутингу і `middleware`, тож rate limiting на рівні Laravel тут не допоможе.

### Які версії Symfony брати

Діапазони вразливих версій охоплюють усе від 4.1 до свіжих релізів. Виправлення вийшли для підтримуваних гілок:

- 5.4: **5.4.54**;
- 6.4: **6.4.48**;
- 7.4: **7.4.21**;
- 8.1: **8.1.9**.

Формально попередження називає першими виправленими 6.4.46, 7.4.19 і 8.1.7, але, як визнає сама Symfony, перша версія фіксу зламала розбиття за пробільним роздільником: `HeaderUtils::split('foo bar', ' ')` у 6.4.46-6.4.47, 7.4.19-7.4.20 і 8.1.7-8.1.8 повертав одне значення замість двох. Тому орієнтуйтеся на версії зі списку вище. У гілці 5.4 цієї регресії не було.

Перевірте, що стоїть у проєкті:

```bash
composer show symfony/http-foundation
composer audit
```

Laravel 12 вимагає `symfony/http-foundation` `^7.2`, Laravel 13 - `^7.4 || ^8.0`, тож в обох випадках виправлена версія доступна без зміни обмежень:

```bash
composer update symfony/http-foundation --with-dependencies
```

Якщо після оновлення `composer show` все одно показує 7.2 чи 7.3, перевірте `composer why-not symfony/http-foundation 7.4.21`: ці гілки вже не підтримуються, і для них виправлень немає. Те саме з 6.0-6.3: треба переходити на 6.4, а це вимагає PHP 8.1.

### Сусід: рекурсія в symfony/yaml

У тому ж пакеті попереджень Symfony опублікувала [GHSA-2v3c-qxhr-7vpv](https://github.com/advisories/GHSA-2v3c-qxhr-7vpv) (CVE-2026-109413). Inline-лексер YAML рекурсивно спускався в кожну `{` і `[`, не враховуючи `maxNestingLevel`, тож документ із глибоко вкладених колекцій вичерпував стек і валив процес.

Laravel сам по собі `symfony/yaml` не використовує, і YAML у запитах не розбирає. Вразливість актуальна, лише якщо ваш код викликає `Yaml::parse()` на даних від користувачів: імпорт конфігурацій, OpenAPI-специфікацій, front matter. Перевірити, чи пакет узагалі є в проєкті і хто його тягне:

```bash
composer why symfony/yaml
```

Виправлені версії: 5.4.54, 6.4.45, 7.4.18 і 8.1.6.

### PhpSpreadsheet: хто під загрозою

PhpSpreadsheet читає XLSX, ODS і SpreadsheetML-XML, а перед розбором XML проганяє вміст через `XmlScanner`, який шукає `<!DOCTYPE` і відкидає файли з оголошеннями сутностей. Цього разу знайшлося три серйозні проблеми:

- [GHSA-3x94-m842-937c](https://github.com/advisories/GHSA-3x94-m842-937c): escape-послідовності ISO-2022 між символами `<!DOCTYPE` ламають регулярний вираз сканера, а XML-парсер потім їх викидає і бачить звичайний DOCTYPE. Зачіпає XLSX, тобто найпоширеніший сценарій.
- [GHSA-rxj4-h86g-25gc](https://github.com/advisories/GHSA-rxj4-h86g-25gc): читач SpreadsheetML (`Reader\Xml`) сканує файл двічі і декодує сутності після кожної перевірки, тож подвійне кодування `<` проходить повз обидві. Лише гілки 3.3+ і 4.x-5.x.
- [GHSA-j2w7-387v-m2rq](https://github.com/advisories/GHSA-j2w7-387v-m2rq): ODS-читач не обмежує атрибут `table:number-rows-repeated` і створює по клітинці на кожен повтор. Файл на 1,4 КБ із 5 мільйонами рядків вичерпує пам'ять.

Для перших двох основний наслідок на сучасному PHP - DoS через розгортання сутностей: за даними попередження, XLSX на 2 КБ з'їдає близько 45 МБ пам'яті. Читання локальних файлів і SSRF через зовнішні сутності блокуються за замовчуванням на PHP 8 з libxml2 2.9+, але стають можливими на PHP 7 або якщо десь увімкнено `LIBXML_NOENT`.

Окремо є [GHSA-2phh-27fw-q4gc](https://github.com/advisories/GHSA-2phh-27fw-q4gc) середньої серйозності: обхід білого списку для зовнішніх зображень через HTTP-редирект. Він стосується лише тих, хто явно вмикає `setAllowExternalImages(true)`.

Під загрозою застосунки, які відкривають таблиці від користувачів: імпорт товарів, контактів, прайсів. У Laravel-світі це насамперед Laravel Excel (`maatwebsite/excel`), який під капотом використовує PhpSpreadsheet.

### Як оновити PhpSpreadsheet

Виправлені версії: **5.10.0**, **3.10.8**, **2.4.8**, **2.1.19** і **1.30.7**. Обмеження Laravel Excel дозволяють дістатися до них звичайним оновленням: гілка 3.1 вимагає `phpoffice/phpspreadsheet` `^1.30.5`, актуальна 4.x - `^5.9`.

```bash
composer show phpoffice/phpspreadsheet
composer update phpoffice/phpspreadsheet
```

Додатково варто звузити, які формати ви взагалі приймаєте. Якщо імпорт розрахований на XLSX і CSV, не дозволяйте ODS і XML у валідації і передавайте тип читача явно, а не покладайтеся на розширення файла:

```php
$request->validate([
  'file' => ['required', 'file', 'mimes:xlsx,csv', 'max:5120'],
]);

Excel::import(new ProductsImport, $request->file('file'), null, \Maatwebsite\Excel\Excel::XLSX);
```

Від обходу через ISO-2022 у XLSX це не захищає, тож оновлення обов'язкове, але прибирає з поверхні атаки два читачі, якими ви не користуєтеся. Важкий імпорт краще виносити в чергу з обмеженням пам'яті воркера: тоді «бомба» вб'є один процес, а не веб-сервер.

Якщо Laravel Excel у проєкті лише для експорту, ризик значно менший: вразливості сидять у читачах. А [Fast Excel](https://laravelukraine.com/blog/fast-excel-ci-laravel-excel-shho-obrati-dlia-velikix-naboriv-danix) працює на OpenSpout, а не на PhpSpreadsheet, і ці попередження його не стосуються.

### Що зробити сьогодні

- Запустіть `composer audit` у кожному проєкті. Він знає про всі попередження з цієї статті.
- Оновіть `symfony/http-foundation` до 5.4.54, 6.4.48, 7.4.21 або 8.1.9. Це стосується кожного Laravel-застосунку, без винятків.
- Якщо приймаєте таблиці від користувачів, оновіть `phpoffice/phpspreadsheet` і звузьте список дозволених форматів.
- `symfony/yaml` оновлюйте, якщо він є в `composer.lock` і розбирає чужі дані.
- Якщо `composer audit` ще не працює у вашому CI, це хороший момент його туди додати: обидві бібліотеки - транзитивні залежності, про які інакше дізнаєшся з новин.
