27 октября 2026 г.

Node2Shell (CVE-2026-111497): как проверить и обновить Node.js на сервере, под PM2 и в Docker

Ошибка Brotli в Node.js 22, 24 и 26 исправлена в 22.23.4, 24.22.1 и 26.12.1. Как проверить сервер, обновить Node.js и перезапустить PM2 и Docker.

21 октября 2026 года проект Node.js выпустил исправление для CVE-2026-111497 — ошибки в декодере Brotli, которую называют Node2Shell. Если на сервере у вас Node.js 22, 24 или 26, задача сводится к двум шагам: поднять версию до 22.23.4, 24.22.1 или 26.12.1 и перезапустить каждое приложение, которое уже работало. Ниже — как проверить версию, как обновить Node.js на сервере через NodeSource, nvm или Docker и почему PM2 после обновления продолжает крутить старую версию.

Коротко. CVE-2026-111497 (Node2Shell) — ошибка в разборе данных, сжатых Brotli. Исправлена в Node.js 22.23.4, 24.22.1 и 26.12.1. Выполните node -v, сверьтесь с таблицей ниже, обновите Node тем же способом, которым ставили (пакеты NodeSource, nvm, образ Docker) и после этого перезапустите всё, что работало до обновления: уже запущенный процесс обновление не затрагивает. Линии 18, 20 и 25 сняты с поддержки и патча не получат. Факты в статье проверены 27 октября 2026 года.

Что такое Node2Shell (CVE-2026-111497)

Brotli — формат сжатия, который браузеры и серверы используют, когда в HTTP-сообщении стоит Content-Encoding: br. В Node.js встроен декодер Brotli. Если в данных попадается недопустимое переключение блока, он принимает это за «нужно ещё входных данных», а не за фатальную ошибку. В зависимости от входа итог бывает разным: сбой процесса, раскрытие его памяти или выполнение кода. Нашла ошибку OpenAI Codex Security. Корень — в библиотеке Brotli от Google, версии 1.0.3-1.2.0 (исправлено в 1.0.10, 1.1.1 и 1.2.1, по данным NVD).

Прежде чем планировать работу, стоит знать две вещи. Оценки серьёзности расходятся: High у проекта Node.js и у Imperva, Critical (CVSS 4.0, 9.2) у автора CVE, Google, в NVD. А эксплуатация в живой среде на 23 октября 2026 года не подтверждена (Sysdig): в каталоге CISA KEV ошибки нет, а оценка CISA в NVD говорит «exploitation: none». После 23 октября мы статус не проверяли. Разумно обновиться спокойно и по плану. Игнорировать — нет.

Какие пути до ошибки достижимы

Декодер срабатывает, только когда ему передают данные Brotli. Источники называют такие пути:

  • Любой код, который распаковывает Brotli через node:zlib — встроенный в Node модуль сжатия.
  • Imperva воспроизвела выполнение кода через ответы fetch() на Node 24.22.0 (на 24.22.1 данные отклоняются) и через тела запросов в Express 5 с body-parser 2.x (raw() и json()).
  • Sysdig добавляет плагин распаковки Fastify, Koa через co-body и прямой вызов createBrotliDecompress().

Голый http-сервер Node сам Brotli в телах запросов не распаковывает, поэтому по умолчанию он не затронут. Но распаковку может включить ваш код или библиотека. Следите за версией body-parser: 2.x распаковывает br по умолчанию (inflate: true), а 1.20.x понимает только gzip и deflate.

Масштаб доказательств лучше держать в голове. Рабочее выполнение кода у Imperva показано на одной конфигурации (Node 24.22.0, Linux arm64, официальный образ) и удавалось не при каждой попытке. Сбой процесса воспроизводится легко. Про Next.js Vercel пишет только это: «For self-hosted Next.js, upgrade Node.js; Next.js does not block Brotli responses in image optimization». Утверждения, что обычная обработка запросов в Next.js уязвима по умолчанию, мы ни в одном первоисточнике не нашли. Правило для всех одно: обновляйте Node.js под любым приложением, особенно под тем, что принимает или запрашивает данные с Brotli.

В каких версиях Node.js ошибка исправлена

Линия

Состояние

Нужная версия

22.x

Исправлено 21 октября 2026

22.23.4 и новее

24.x

Исправлено 21 октября 2026

24.22.1 и новее

26.x

Исправлено 21 октября 2026

26.12.1 и новее

25.x

Снята с поддержки 31 марта 2026

Патча нет: переходите на исправленную линию

20.x

Снята с поддержки 24 марта 2026

Патча нет: переходите на исправленную линию

18.x

Снята с поддержки 27 марта 2025

Патча нет: переходите на исправленную линию

Проект Node.js формулирует прямо: «End-of-Life versions are always affected when a security release occurs». Переход с 18 или 20 на новую линию — это смена мажорной версии со своими несовместимостями, так что сначала прогоните его на запасном сервере, а не на боевом. Запасной сервер поднимается за несколько минут: как создать сервер в панели HIP показывает шаги.

Как проверить версию Node.js на сервере

Зайдите на сервер по SSH. node -v печатает версию, которую находит ваша оболочка. which node показывает файл за ней, а readlink -f проходит по символическим ссылкам до настоящего места (здесь обе строки совпали). apt-cache policy nodejs показывает установленный пакет и самый свежий из ваших репозиториев.

  • Installed — то, что у вас стоит; Candidate — то, что поставит apt. Кандидат выше установленного значит, что обновление ждёт (сначала выполните apt-get update, чтобы список был свежим).
  • Суффикс nodesource1 говорит, что пакет пришёл из репозитория NodeSource.

Это показывает, что запустит новый процесс. Что используют уже работающие приложения, вывод не говорит. Эта разница — главная тема раздела про PM2 ниже.

Откуда у вас Node.js

Способ обновления зависит от того, как Node попал на машину, поэтому сначала определите это.

Как установлен

Как узнать

Чем обновлять

Репозиторий NodeSource (apt)

apt-cache policy nodejs показывает версию с nodesource1 на конце

apt-get install --only-upgrade nodejs

nvm (менеджер версий Node)

which node ведёт в ~/.nvm/versions/node/

nvm install 22 (или ваша линия)

Пакет дистрибутива

Версия вроде 18.19.1+dfsg-6ubuntu5

Зависит от дистрибутива, см. ниже

Образ Docker

FROM node:... в Dockerfile

Пересобрать на исправленном теге

Node.js из репозитория дистрибутива

Дистрибутивы обычно кладут в репозиторий свой, нередко более старый пакет nodejs, и вердикт тут определяет не номер версии. Трекер Ubuntu помечает nodejs на 22.04 и 24.04 как «Not affected»: эти пакеты используют системную libbrotli, а исправление вошло в libbrotli1. На Ubuntu 20.04 трекер пишет «Vulnerable». Трекер Debian помечает nodejs в bookworm и trixie как уязвимый, хотя пакеты brotli там уже исправлены. Это статусы трекеров на 27 октября 2026 года, и они меняются. Кандидаты в чистых образах в тот день:

Выпуск

Кандидат nodejs

Статус в трекере, 27.10.2026

Кандидат libbrotli1

Ubuntu 22.04

12.22.9~dfsg-1ubuntu3.6

Not affected

1.0.9-2ubuntu0.1

Ubuntu 24.04

18.19.1+dfsg-6ubuntu5

Not affected

1.1.0-2ubuntu0.1

Debian 12 (bookworm)

18.20.4+dfsg-1~deb12u3

Vulnerable

1.0.9-2+deb12u1

Debian 13 (trixie)

20.19.2+dfsg-1+deb13u3

Vulnerable

1.1.0-2+deb13u1

На Ubuntu команда apt-cache policy libbrotli1 покажет, стоит ли исправленная библиотека. На Debian считайте пакетный Node необновлённым, пока трекер не скажет обратного, и помните, что пакетные линии (18 и 20) — как раз те, что сняты с поддержки, см. таблицу выше. Проще всего уйти на поддерживаемую линию из NodeSource, nvm или Docker. Для других выпусков откройте трекер своего выпуска.

Как обновить Node.js на Ubuntu из пакетов NodeSource

NodeSource — сторонний репозиторий apt со свежими сборками Node.js. В его репозитории node_22.x лежит 22.23.4-1nodesource1: на нашем стенде apt-cache policy nodejs показал её кандидатом. Две команды выполняйте от root или через sudo. Первая обновляет списки пакетов, вторая обновляет nodejs, только если он уже установлен, так что случайно ничего лишнего не поставит:

apt-get update
apt-get install --only-upgrade -y nodejs

Вывод второй команды длинный. На некоторых серверах в конце стоит посторонняя заметка, например о перезагрузке для нового ядра. Она не про Node. Важна проверка после:

Первая команда показывает ожидающее обновление (её запускают до обновления). Вторая печатает новую версию, когда обновление сделано. Новая оболочка теперь получает исправленный Node. Работающие приложения — нет, об этом сразу ниже.

Как обновить Node.js через nvm

nvm ставит версии Node.js в вашу домашнюю папку и переключает их для каждой оболочки. Через apt он не работает. nvm install 22 берёт последнюю 22.x. В нашем запуске он скачал архив с nodejs.org и сверил контрольную сумму:

В новых оболочках эта версия сама не включится, пока вы не зададите алиас по умолчанию. Заодно посмотрите на nvm ls: старая версия остаётся установленной рядом с новой.

В пути есть номер версии. Если файл службы или команда PM2 указывает на старую папку (.../v22.23.2/bin/node), это приложение остаётся на старом Node, пока вы не поправите путь. Проверьте, куда смотрит ваше.

Как обновить Node.js в Docker

Образ Docker — упакованный шаблон, в котором Node.js уже лежит внутри, а контейнер — его работающая копия. Обновление Node на хосте контейнерам ничего не даёт: у каждого свой. Значит, нужен новый образ и свежий контейнер. Сначала посмотрите, что запущено. Цикл ниже спрашивает у каждого работающего контейнера версию Node; || echo no-node прикрывает контейнеры, где Node нет.

В Dockerfile закреплён точный тег node:22.23.2-alpine, поэтому одна пересборка ничего не изменит: тег по-прежнему означает 22.23.2. Вариантов два. Точный исправленный тег (node:22.23.4-alpine; теги 22.23.4, 24.22.1 и 26.12.1 существуют с вариантами -slim, -alpine, -bookworm и -trixie) даёт воспроизводимые сборки, но к следующему выпуску его придётся править заново. Плавающий тег вроде node:22-alpine уже указывает на исправленную сборку (мы проверили: v22.23.4) и подхватывает будущие исправления при пересборке. Наше мнение: плавающий тег — для небольших сервисов, которые вы часто пересобираете, точный — там, где нужны воспроизводимые сборки. В примере мы переходим на плавающий и собираем с --pull: эта опция велит Docker проверить, нет ли более нового базового образа, а не брать закешированный:

Собранный образ ничего не меняет, пока из него не запущен контейнер. docker restart поднял бы старый образ, поэтому контейнер удаляют и запускают новый. docker rm -f стирает всё, что лежало только внутри контейнера, так что данные держите в томах. Порт и имя ниже — из примера, подставьте свои.

Почему PM2 после обновления работает на старом Node.js

PM2 — менеджер процессов для приложений на Node: запускает их, поднимает после падения и ведёт список. Запущенный процесс в Linux держит тот исполняемый файл, с которого стартовал. Когда apt заменяет /usr/bin/node, старого файла на диске уже нет, но приложение, которое работает, продолжает идти с него. Обновление выглядит завершённым (node -v говорит 22.23.4), а приложение остаётся на уязвимой сборке.

Мы воспроизвели это на крошечном приложении, которое отвечает собственным process.version и запущено под PM2 на 22.23.2. Первая команда в карточке выполнена до обновления, вторая и третья — после. /proc/PID/exe — ссылка на файл, с которого запущен процесс, а (deleted) значит, что файла с таким именем уже нет. PID можно получить командой pm2 pid <имя>; n2s — имя нашего примера, подставьте своё.

В этом и ловушка: в вашей оболочке зелёный node -v, а приложение на той же машине в ту же минуту отвечает ok v22.23.2. Лечится перезапуском приложения. После pm2 restart приложение отвечает новой версией, а новый процесс указывает на обычный файл:

Фоновый демон самого PM2 — тоже долгоживущий процесс, так что после обновления его стоит освежить командой pm2 update. В нашем запуске приложение вернулось в статус online с uptime 0s и новым PID; новый Node в приложение к этому моменту уже привёл перезапуск выше.

Та же логика действует для всего долгоживущего, что стартовало до обновления: службы systemd, воркера, скрипта в сеансе screen. Перезапустите его привычным для вас способом. Полезная привычка: пусть приложение где-нибудь показывает process.version (страница проверки состояния, строка в логе при старте), как наш пример. Тогда вы проверяете работающий процесс, а не файл на диске. Если нужно понять, какой процесс держит какой порт, поможет статья ss вместо netstat.

Что делать, если обновиться сегодня нельзя

Дыру закрывает только обновление. Перечня обходных мер Node.js сам не публикует. Sysdig и Imperva называют частичные меры, которые снижают риск, пока вы планируете работу. Ни одна из них обновление не заменяет:

  • Если у вас Express с body-parser 2.x, задайте express.json({ inflate: false }). Сжатые тела тогда получат ответ 415 (неподдерживаемый тип). Сначала проверьте клиентов: всё, что шлёт сжатые тела, начнёт получать отказ.
  • Отклоняйте Content-Encoding: br во входящих запросах на прокси.
  • Запускайте Node под непривилегированным пользователем и не держите секреты в окружении процесса, чтобы успешная атака получила меньше.

Эти меры закрывают не все пути из списка выше. Например, fetch() к серверу, который отвечает Brotli, правило для входящих запросов не касается. Если базовая защита этого сервера у вас ещё не сделана, начните с руководства по настройке за первый час.

Частые вопросы

Насколько опасна CVE-2026-111497?

Оценки расходятся. Проект Node.js и Imperva ставят High, автор CVE, Google, — Critical с оценкой CVSS 4.0, равной 9.2, в NVD. Какие пути достижимы, зависит от вашего приложения, поэтому обновляйтесь по плану и не ждите, пока оценки сойдутся.

Эксплуатируют ли Node2Shell в живой среде?

На 23 октября 2026 года Sysdig сообщал, что подтверждённых случаев нет, ошибки нет в каталоге CISA KEV, а оценка CISA в NVD говорит «exploitation: none». Позже мы статус не проверяли, так что перед решением о срочности загляните в источники ещё раз.

Касается ли это Next.js и простого http-сервера?

Голый http-сервер Node сам Brotli в телах запросов не распаковывает. По самоуправляемому Next.js Vercel советует обновить Node.js и отмечает, что Next.js не блокирует ответы Brotli при оптимизации изображений. Ни один из прочитанных источников не говорит, что обычная обработка запросов в Next.js уязвима по умолчанию. Всё равно обновите Node: что достижимо, решают ваши зависимости.

Я обновил Node.js, почему приложение показывает старую версию?

Работающий процесс держит старый файл до перезапуска. Выполните pm2 restart для каждого приложения (или перезапустите службу), а контейнеры Docker пересоберите и создайте заново. Затем проверьте версию изнутри работающего приложения.

Что делать на Node.js 18 и 20?

Эти линии сняты с поддержки, патча от проекта Node.js на них нет. Перейдите на исправленную линию (22.23.4, 24.22.1 или 26.12.1) после пробного прогона на запасном сервере. Если у вас пакет дистрибутива, посмотрите свой выпуск в трекере, как в таблице выше.

Коротко

  • CVE-2026-111497 (Node2Shell) исправлена в Node.js 22.23.4, 24.22.1 и 26.12.1; линии 18, 20 и 25 патча не получат.
  • Выясните, как установлен ваш Node (NodeSource, nvm, дистрибутив, Docker), и идите по своему пути обновления.
  • Обновление не меняет работающие процессы. Перезапустите приложения PM2 и службы, пересоберите и пересоздайте контейнеры.
  • Проверяйте работающее приложение, а не только node -v: смотрите /proc/PID/exe на (deleted) или пусть приложение само сообщает process.version.
  • Частичные меры обновление не заменяют.

Источники

  • Node.js, октябрьские релизы безопасности 2026: https://nodejs.org/en/blog/vulnerability/october-2026-security-releases
  • Релизы Node.js и даты конца поддержки: https://nodejs.org/en/about/previous-releases
  • Также использованы: разборы Imperva и Sysdig, запись NVD по CVE-2026-111497, заявление Vercel про самоуправляемый Next.js, трекеры безопасности Ubuntu и Debian (статусы на 27 октября 2026 года).
PUBLISHED
27 октября 2026 г.
AUTHOR
HIP-HOSTING
LANGUAGES
EN · RU