Дайджесты новостей
Драматичный светотеневой натюрморт с сетевым контроллером и осциллографом, символизирующими защиту от DoS-уязвимости в Fastify.

Fastify 5.12.8 и 6.0.0-alpha.6: патч уязвимости GHSA-3qgw-9275-xf8w и компиляция роутера

Если ты строишь высоконагруженные сервисы на Node.js, веб-фреймворк Fastify вряд ли нуждается в представлении. Архитектурный фокус на экстремальной пропускной способности, валидации через JSON Schema и строгой компоновке плагинов сделали его де-факто стандартом для микросервисов. Однако в начале ноября 2026 года команда мейнтейнеров под руководством Маттео Коллины (Matteo Collina) выпустила скоординированные обновления сразу двух веток: стабильный корректирующий релиз Fastify v5.12.8 и альфа-сборку следующего мажорного поколения Fastify v6.0.0-alpha.6.

Поводом для срочного выпуска стало закрытие уязвимости отказа в обслуживании (Denial of Service), зарегистрированной как GHSA-3qgw-9275-xf8w (CVE-2026-120216). Но под капотом этих релизов спрятано кое-что еще более интересное — долгожданная опция предварительной компиляции роутера, способная дать ощутимый прирост производительности на сложных маршрутах.

Анатомия уязвимости GHSA-3qgw-9275-xf8w: ловушка потоковых ответов

Парадокс этой уязвимости в том, что к аварии приводила штатная защитная механика. У Fastify есть параметр handlerTimeout, который по умолчанию отключен (0), но часто выставляется инженерами в продакшене (например, в 5 или 10 секунд), чтобы спасать сервер от утечек памяти при зависании внешних запросов к базам данных.

Проблема возникала на маршрутах, возвращающих потоковые данные (streaming responses через ReadableStream или генераторы). В современных проектах это практически каждый второй сервис: потоковая отдача токенов из больших языковых моделей (LLM streaming), Server-Sent Events (SSE) для живых уведомлений или выгрузка тяжелых отчетов клиенту.

Сценарий сбоя развивался по следующей цепочке:

  1. Клиент подключается к эндпоинту, сервер начинает отдавать поток. HTTP-заголовки со статусом 200 OK успешно улетают в сокет.
  2. Из-за сетевой задержки или паузы в генерации токенов передача тела ответа затягивается сверх лимита handlerTimeout.
  3. В ядре Fastify срабатывает таймер таймаута обработчика. Фреймворк решает, что запрос завис, и пытается отправить клиенту стандартную ошибку 504 Gateway Timeout.
  4. Внутренний метод reply.send() пытается записать статус ошибки в сокет, в который заголовки уже были отправлены на первом шаге.
  5. Node.js выбрасывает фатальное исключение ERR_HTTP_HEADERS_SENT. Поскольку событие происходило внутри асинхронного колбэка таймера ядра, оно оказывалось неперехваченным, и рабочий процесс Node.js мгновенно падал, обрывая все параллельные клиентские сессии.

Злоумышленнику было достаточно открыть соединение на стриминговый эндпоинт и искусственно замедлить чтение TCP-пакетов, чтобы отправить в рестарт все инстансы сервиса.

Обновление и временный воркэраунд

Патч в версиях v5.12.8 и v6.0.0-alpha.6 добавляет строгую проверку флагов отправки заголовков (reply.raw.headersSent) перед попыткой сгенерировать ответ об ошибке таймаута: соединение аккуратно финализируется без падения процесса.

Для устранения уязвимости достаточно обновить зависимость в проекте:

# Обновление стабильной ветки 5.x
npm install fastify@^5.12.8

# Либо установка альфы следующего мажорного поколения
npm install fastify@6.0.0-alpha.6

Если по каким-то причинам твоя команда не может выкатить свежий релиз немедленно (например, идет период заморозки кода перед релизом продукта), Маттео Коллина рекомендует временный воркэраунд — явно отключить таймаут обработчика на уровне инстанса:

// Временная защита до наката патча: сброс таймаута обработчика
const fastify = require('fastify')({
  handlerTimeout: 0 // отключает внутренний таймер, исключая ошибку ERR_HTTP_HEADERS_SENT
});

Компиляция роутера: режим find-my-way compile

Пока патч безопасности спасает стабильную ветку, второе важное новшество адресовано любителям выжимать каждый процент производительности. В Fastify интегрирована поддержка предварительной компиляции дерева маршрутов через опцию routerOptions.compile (PR #7096 и #7116 от Matteo Collina и Tony133).

Исторически роутер find-my-way использовал алгоритм префиксного дерева (Radix Tree). На каждом входящем запросе алгоритм рекурсивно обходил узлы дерева, извлекая параметры пути. В новом режиме дерево путей при инициализации сервера компилируется в монолитный JavaScript-код с оптимизированными условиями и кэшированными регулярными выражениями:

const fastify = require('fastify')({
  routerOptions: {
    compile: true // активирует предварительную компиляцию дерева маршрутов
  }
});

// Роуты с параметрами и wildcard-сегментами матчатся быстрее
fastify.get('/api/users/:userId/orders/:orderId', async (request, reply) => {
  return {
    userId: request.params.userId,
    orderId: request.params.orderId
  };
});

На синтетических тестах с сотнями зарегистрированных API-эндпоинтов предварительная компиляция ускоряет выбор маршрута на 15–25%, приближая скорость Node.js к нативным серверам на C++ и Rust. Подобные оптимизации особенно актуальны при построении модульных систем на базе современных фреймворков вроде NestJS, использующих Fastify под капотом.

Улучшения TypeScript и границы шестой версии

Помимо безопасности и компиляции, релиз принес порцию полезных исправлений в типах:

  • Контекст this в шорткодах хуков: в методах onRequest, preParsing и других хуках, объявляемых внутри конфигурации маршрута, восстановлена строгая типизация ссылки на экземпляр FastifyInstance.
  • Интерфейс logSerializers: добавлен в RouteShorthandOptions, что позволяет переопределять кастомные сериализаторы логов Pino для конкретного эндпоинта.
  • Поддержка UNIX-сокетов: аргументы слушателя теперь штатно принимают пути к сокетам Unix в строковом формате.
  • Безопасные статусы ответов: код statusCode теперь строго клэмпится в диапазоне от 400 до 599, предотвращая краш при передаче некорректных чисел.
Ограничения ветки Fastify v6.0.0-alpha.6

Не торопитесь переводить продакшен на альфа-ветку шестой версии: в ней уже появились ломающие изменения (breaking changes). В частности, из стандартных ошибок валидации JSON Schema по умолчанию исключен стек вызовов (stack trace) для защиты от утечки внутренней архитектуры и снижения оверхеда. Используйте альфу только для локального тестирования совместимости плагинов.

В итоге мы получили образцовый релиз: критическая DoS-дыра закрыта без промедлений, стабильная ветка 5.x надежно защищена, а контуры будущей Fastify 6 обещают еще более высокую скорость маршрутизации.