Node.js закрыл 10 CVE: четыре — в модели разрешений
29 июля 2026 года проект Node.js выпустил сразу три релиза безопасности — 22.23.2, 24.18.1 и 26.5.1 — закрыв десять CVE на всех поддерживаемых линиях. Само число показательно, но важнее его распределение: четыре уязвимости из десяти находятся в модели разрешений — том самом механизме, на который многие команды теперь полагаются, чтобы ограничить возможности одного процесса.
Проблема: модель разрешений принимают за песочницу
Модель разрешений появилась в Node.js 20 с привлекательной идеей. Запусти процесс с --permission, выдай ровно то, что нужно — чтение из одного каталога, запись в другой, без сети и без дочерних процессов — и радиус поражения от сборочного скрипта или случайного postinstall сжимается почти до нуля. По мере роста тревоги вокруг цепочки поставок флаг начал появляться в конфигурациях CI и точках входа контейнеров уже как средство защиты.
Документация Node.js всегда формулировала это аккуратнее. Модель описана как ремень безопасности для доверенного кода, а не как барьер против вредоносного: Node.js доверяет любому коду, который его просят выполнить. «Предотвращает случайную ошибку» и «останавливает атакующего» — разные гарантии, и этот релиз сделал разрыв между ними наглядным.
Что изменилось
Главная находка — CVE-2026-58043 с оценкой High. Процесс, которому выдали доступ на чтение или запись к одному каталогу, мог воспользоваться сопоставлением префиксов в используемом внутри radix-дереве и читать или писать за пределами белого списка. То есть --allow-fs-read=/srv/app/data означал не то, чем выглядел, — классический обход через выход за пределы пути.
Рядом с ней две менее серьёзные: CVE-2026-56847 и CVE-2026-58039 позволяли trace events и диагностическим отчётам писать вывод в произвольные места на диске. Тот же выход за белый список, только со стороны вывода, а не ввода.
За пределами модели разрешений практически опаснее выглядит HTTP/2. CVE-2026-56848 — это use-after-free в куче в nghttp2_session_mem_send(), достижимый через повторные вызовы во время обработки сообщения, с удалённым выполнением кода как потолком риска. На линиях 22.x и 24.x добавляется CVE-2026-56846: блоки заголовков обходят заданные лимиты памяти и истощают память сессии. Остальное — средние и низкие находки в https, sqlite, dns, zlib и http, плюс обновления зависимостей: llhttp до 9.4.3 и undici до 8.9.0.
Практический пример: флаг не должен быть единственной границей
Обновление обязательно, но архитектурный вывод переживёт сам патч. Общее правило: любая гарантия безопасности, стоящая на одном слое, — гарантия временная. Если каталог с данными и есть граница, которую нельзя пересекать, эта граница должна быть записана и в коде приложения, а не только в команде запуска. А затем — спрашивать модель разрешений вместо того, чтобы догадываться, что она выдала.
// docs.js
import { readFile } from 'node:fs/promises';
import { resolve } from 'node:path';
const ROOT = '/srv/app/data';
// Слой первый: явная проверка вложенности
function safePath(userInput) {
const target = resolve(ROOT, userInput);
if (target !== ROOT && !target.startsWith(ROOT + '/')) {
throw new Error('path escapes data root');
}
return target;
}
export async function readDoc(name) {
const path = safePath(name);
// Слой второй: спрашиваем, а не предполагаем
if (!process.permission.has('fs.read', path)) {
throw new Error(`fs.read not granted: ${path}`);
}
return readFile(path, 'utf8');
}Запуск с минимально необходимыми правами — и сначала проверка версии:
node --permission --allow-fs-read=/srv/app/data ./server.js
node -p "process.versions.node"
# 22.x → 22.23.2 | 24.x → 24.18.1 | 26.x → 26.5.1Оговорки из практики
- Линии, снятые с поддержки (EOL), тоже затронуты и патчей не получат. На 20.x и старше единственное решение — обновление.
- Находки в HTTP/2 касаются всех, кто отдаёт
http2напрямую, и тех, у кого прокси доносит HTTP/2 до самого origin. Проверьте границу, прежде чем считать себя закрытым. process.permission.has()— полезная защитная проверка, но не замена валидации ввода. Нужны оба слоя, а не один из них.- Это вторая крупная волна патчей за ту же неделю после релиза безопасности Next.js. Свести их в одно окно обслуживания дешевле, чем разносить на два.
Вывод
Обновляйтесь сейчас: 22.23.2, 24.18.1 или 26.5.1 — в зависимости от линии. А затем пересмотрите места, где --permission тихо повысили из ремня безопасности до границы безопасности. Механизм полезен и будет развиваться, но ремнём безопасности его называют не случайно — и архитектура на двух независимых слоях остаётся стоять, когда один из них уступает.
Первоисточник: Node.js — Wednesday, July 29, 2026 Security Releases