# Next.js 16.4.5/15.5.29 і Node.js security release: сім дір у кеші та що робити зараз

> Next.js закрив 7 вразливостей у Cache Components і Image Optimization, Node.js готує реліз 11 листопада. Розбір impact і план патчингу.

- Автор: Юра Скиба (https://cookiesoftware.io)
- Опубліковано: 2026-11-04
- Категорія: React і Frontend
- Canonical: https://cookiesoftware.io/blog/nextjs-nodejs-security-november-2026

---
Next.js 3 листопада випустив патчі v16.4.5 (Active LTS) і v15.5.29 (Maintenance LTS), що закривають сім вразливостей – одну High severity і шість Medium. Усі вони так чи інакше пов’язані з Cache Components, Edge Route Handlers і Image Optimization. Паралельно Node.js анонсував окремий security release на 11 листопада для ліній 26.x, 24.x і 22.x, де найвища severity теж позначена як High – але конкретних CVE поки не розкрили.

Про сам факт анонсу Next.js-релізу ми вже писали в [попередньому матеріалі](/blog/nextjs-november-2026-security-release), коли деталі ще не були опубліковані. Тепер вони є, і варто розібрати, що саме змінилось і кого це реально стосується.

## Чому це не просто "ще один патч у changelog"

Якщо твій застосунок на Next.js використовує Cache Components, `use cache` або `unstable_cache` – ти в зоні ризику за замовчуванням, просто тому що ці механізми активно просуваються як рекомендований підхід до кешування (про це ми писали в розборі [Cache Components як дефолту](/blog/nextjs-16-4-cache-components) і в [ментальній моделі кешу Next.js](/blog/nextjs-cache-mental-model)). Найсерйозніша з вразливостей цього релізу – якраз про те, що один орендар (tenant) у мультитенантному застосунку міг отримати закешовані дані іншого орендаря.

Для продуктів, де tenant isolation – це частина контракту з клієнтом (SaaS, B2B-платформи, white-label рішення), це не теоретична дірка, а пряме порушення обіцянки "дані одного клієнта ніколи не бачить інший". Навіть якщо в тебе немає explicit multi-tenancy, подібні патерни трапляються там, де кеш розрізняє контент за локаллю, сайтом чи акаунтом користувача.

## Що саме полагодили

Головна вразливість (High) стосується ситуації, коли та сама публічна `use cache` функція викликається і напряму, і обгорнута в `unstable_cache`. Якщо функція читає root-параметр на кшталт tenant ID, під час холодного заповнення кешу конкурентний виклик через `unstable_cache` може не перевірити root-параметр і отримати результат чужого запиту. Цей результат потім зберігається і віддається наступним викликам з тими самими аргументами, поки кеш не оновиться чи не витече.

Шість medium-вразливостей охоплюють суміжні сценарії:

- **Вкладені `use cache` функції** можуть передати контент одного root-параметра (tenant, site, locale) запитам для іншого, якщо зовнішня функція завершується раніше, ніж внутрішня встигає записати залежності від root-параметра.
- **Бінарні аргументи в `use cache`** можуть колізувати за cache identity: різні за змістом binary-аргументи дають однаковий ключ кешу, і якщо вони використовуються для розрізнення користувачів – один користувач може отримати чужий кешований результат.
- **Shared shell poisoning** у self-hosted застосунках з `next start`, увімкненими Cache Components і вимкненим Partial Prefetching: неавтентифікований запит з підготовленим URL може зіпсувати спільну page shell для інших URL, спричиняючи неправильний рендер або постійні 404.
- **Response injection через stale compressed framing** – якщо застосунок пересилає attacker-controlled fetched Response без змін, за HTTP/1.1 реверс-проксі з pipelined-запитами на спільному backend-з’єднанні можна підмінити, кому дістанеться яка відповідь.
- **Витік cookie через внутрішній заголовок** `x-middleware-set-cookie` в App Router Edge Route Handlers і Pages Router Edge API routes: той самий origin JavaScript може прочитати значення cookie, навіть якщо вона позначена HttpOnly. Node.js Route Handlers і `cookies().set()` цю проблему не зачіпають.
- **SVG rejection bypass в Image Optimization** – зображення з дозволеного джерела можна помилково класифікувати як AVIF, і бекенд оптимізації в підсумку декодує оригінальні байти як SVG, обходячи `images.dangerouslyAllowSVG: false`.

## Як це виглядає в коді

Джерело прямо описує проблемний патерн: та сама `use cache`-функція викликається і напряму, і через `unstable_cache`. Умовно це виглядає так:

```ts
// lib/tenant-settings.ts
import { unstable_cache } from "next/cache";

async function getTenantSettings(tenantId: string) {
  "use cache";
  // функція читає tenantId як root-параметр кешу
  return fetchSettingsFromDb(tenantId);
}

// Виклик напряму, десь у Server Component:
const settings = await getTenantSettings(tenantId);

// Той самий getTenantSettings, обгорнутий в unstable_cache десь-інде:
const cachedSettings = await unstable_cache(
  getTenantSettings,
  ["tenant-settings"]
)(tenantId);
```

Саме комбінація "та сама функція викликається двома шляхами" і створює вікно для гонки під час cold cache fill. Практичний крок після оновлення версій – пройтися кодовою базою і перевірити: чи є у тебе `use cache` функції, які одночасно викликаються напряму і обгортаються в `unstable_cache`. Якщо так – варто або прибрати дублювання викликів, або явно розділити ці шляхи так, щоб root-параметр завжди валідувався перед поверненням результату.

Оновлення залежностей виглядає стандартно:

```bash
npm install next@15.5.29   # для гілки 15.5
npm install next@16.4.5    # для гілки 16.5
```

Для перевірки конкретних вразливостей зручно шукати застосунок за ознаками: чи увімкнені Cache Components, чи є Edge Route Handlers, що ставлять cookie через `NextResponse.cookies.set()`, чи дозволено `images.dangerouslyAllowSVG`.

## Чесні обмеження патчу

Не всі описані issues зачіпають кожен застосунок однаково. SVG-баг вимагає, щоб бекенд оптимізації зображень взагалі вмів декодувати SVG – це not universal. Response injection через stale framing спрацьовує тільки за конкретної поведінки HTTP/1.1 реверс-проксі з pipelined-запитами на спільному з’єднанні – це не стосується кожної конфігурації проксі. Shared shell poisoning вимагає специфічної форми route: prerenderable динамічний параметр без build-time значення, щонайменше два глибші параметри, які ніколи не prerender-яться, і blocking fallback shell з читанням параметра всередині Suspense boundary. Якщо твій застосунок не підпадає під ці умови – ризик нижчий, але сам факт патчингу не завадить.

Trade-off тут простий: оновлення мінорної версії виглядає дешево, але варто прогнати регресійні тести саме на multi-tenant і auth-сценаріях, бо зміни в поведінці кешу можуть вплинути на те, що саме повертається з `use cache` і `unstable_cache` навіть у коректних викликах.

## Коли патчити негайно, а коли можна в наступному спринті

Патч потрібен прямо зараз, якщо:

- у застосунку увімкнені Cache Components і є multi-tenant, multi-site чи multi-locale логіка;
- є Edge Route Handlers або Pages Router Edge API routes, що ставлять cookie через `NextResponse.cookies.set()`;
- застосунок self-hosted через `next start` з Cache Components і без Partial Prefetching;
- Image Optimization працює з користувацькими джерелами зображень і native image backend.

Якщо нічого з переліченого не про твій проєкт – оновлення все одно варте того, щоб потрапити в найближчий реліз, просто без режиму "зупинити все й патчити зараз".

Щодо Node.js: деталі з’являться ближче до 11 листопада або одразу після релізу, зараз відомо лише, що найвища severity позначена як High для ліній 26.x, 24.x і 22.x. Якщо хочеш отримати сповіщення одразу, як з’являться подробиці – підпишись на nodejs-sec mailing list, посилання є в офіційному блозі Node.js.

Фінальний практичний крок простий: онови Next.js до патченої версії цього тижня, окремо запланюй рев’ю коду на предмет подвійних викликів `use cache`-функцій (напряму і через `unstable_cache`), і постав собі нагадування перевірити деталі Node.js-релізу після 11 листопада – там може знайтися щось, що вплине на твій deployment pipeline ще до кінця місяця.
