- Next.js
- Güvenlik
- Frontend
- Test Otomasyonu
Next.js Kasım 2026 Güvenlik Güncellemesi: 7 Açık, Kimler Etkileniyor ve Nasıl Test Edilir?
Next.js 16.4.5 ve 15.5.29 ile kapatılan 7 güvenlik açığı: use cache sızıntıları, SVG bypass, HttpOnly çerez ifşası. Etkileniyor musunuz, nasıl test edersiniz?
Tahir Can Yıldız12 dk okuma
Next.js ekibi 3 Kasım 2026'da 16.4.5 ve 15.5.29 sürümleriyle yedi güvenlik açığını kapattı. Yedisi de "orta" (moderate) önem seviyesinde; dördü yalnızca 16.x hattındaki 'use cache' önbelleğini, üçü ise 15.x hattını da etkiliyor. Bu yazıda her açığın hangi koşulda tetiklendiğini resmi güvenlik bildirimlerine dayanarak açıklıyorum, projenizin etkilenip etkilenmediğini birkaç komutla nasıl kontrol edeceğinizi gösteriyorum ve yamanın gerçekten işe yaradığını doğrulamak için yazabileceğiniz Playwright testlerini paylaşıyorum.
Kısa cevap: hangi sürüme geçmeli?
Yamalar kümülatif; yani hedef sürüme geçtiğinizde Ekim ayındaki kritik düzeltmeleri de almış olursunuz. Sürüm notlarına göre durum şöyle:89

| Kullandığınız hat | Etkilenen sürümler | Geçilecek sürüm |
|---|---|---|
| Next.js 16.x | 16.4.4 ve öncesi | 16.4.5 veya üstü (güncel: 16.4.6) |
| Next.js 15.x | 15.5.28 ve öncesi | 15.5.29 (npm'de backport etiketi) |
| Next.js 14 ve öncesi | Yanıt karışması açığı (GHSA-pc58) alt sınır olmadan tüm eski sürümleri kapsıyor | Yama yok; 15.5.29'a veya 16.x'e geçiş gerekiyor |
Yedi açık tek bakışta
Aşağıdaki tablo, bildirimlerdeki etkilenen sürüm aralıklarını ve açığın ortaya çıkması için gereken koşulları özetliyor. Koşul sütunu, projenizin gerçekten risk altında olup olmadığını anlamanın en hızlı yolu.
| Bildirim | Ne oluyor? | Etkilenen | Koşul |
|---|---|---|---|
| GHSA-mfr8 CVE-2026-119790 | Root param'lar arasında önbellek verisi sızıyor | 16.3.0 – 16.4.4 | Aynı 'use cache' fonksiyonu hem doğrudan hem unstable_cache() içinden çağrılıyor |
| GHSA-vc7v CVE-2026-119351 | İç içe önbellekte root param anahtardan düşüyor | 16.2.0 – 16.4.4 | Cache Components açık, iç fonksiyon root param okuyor ve bekleyen promise döndürüyor |
| GHSA-rhh4 CVE-2026-119349 | Farklı argümanlar aynı önbellek anahtarını üretiyor | 16.0.0 – 16.4.4 | 'use cache' fonksiyonuna Uint8Array veya Blob geçiliyor |
| GHSA-vvgp CVE-2026-119350 | Paylaşılan fallback shell zehirleniyor | 16.4.0 – 16.4.4 | cacheComponents: true, Partial Prefetching kapalı, next start ile self-hosted |
| GHSA-pc58 CVE-2026-119348 | İstemciler arasında yanıt karışıyor | ≤ 15.5.28, 16.0.0 – 16.4.4 | Self-hosted, upstream yanıtı aynen döndüren route, pipelining'e izin veren HTTP/1.1 ters vekil |
| GHSA-7qx7 CVE-2026-119347 | Kapalı olan SVG işleme atlatılıyor | 15.0.0 – 15.5.28, 16.0.0 – 16.4.4 | Self-hosted, /_next/image kullanılıyor |
| GHSA-f3mh CVE-2026-119346 | HttpOnly çerez yanıt başlığında görünüyor | 15.0.0 – 15.5.28, 16.0.0 – 16.4.4 | Edge runtime route'unda NextResponse ile çerez yazılıyor |
'use cache' tarafındaki dört açık
Bu dört açığı anlamak için önce root param kavramına bakmak gerekiyor. Root param'lar, kök layout'un (root layout) route parametreleridir; uygulamalar bunları genellikle veriyi kapsamlamak için kullanır. En yaygın örnek /[locale]/... yapısındaki dil parametresidir.1 Bir 'use cache' fonksiyonu root param okuyorsa, önbellek anahtarının o değeri de içermesi gerekir; aksi halde Türkçe için üretilen içerik İngilizce isteğe de sunulur.

1. unstable_cache() içinden çağrılan 'use cache' (GHSA-mfr8)
Aynı 'use cache' fonksiyonu hem render sırasında doğrudan hem de unstable_cache() üzerinden çağrılıyorsa ve fonksiyon bir root param okuyorsa, önbellek verisi root param değerleri arasında sızabiliyor.1
Bildirime göre sorun bir yarış durumundan kaynaklanıyor: süreç yeni başladığında (cold start), istekler arası tekilleştirme (deduplication) bir unstable_cache() çağrısının, eş zamanlı bir doğrudan çağrının devam eden doldurma işlemine katılmasına izin veriyor. Bu sırada normalde çağrıyı reddedecek root param kontrolü atlanıyor ve sonuç root param içermeyen bir anahtarla saklanıyor. Giriş yeniden doğrulanana ya da silinene kadar diğer dillere de aynı veri dönüyor.
Önemli ayrıntı: bu yarış penceresinin dışında Next.js zaten 'use cache' inside unstable_cache() is unsupported hatası veriyor. Bu iç içe kullanımı kaldırmak, bildirimde resmi ve tam bir geçici çözüm olarak belirtiliyor.
// Kaçınılması gereken kalıp: aynı 'use cache' fonksiyonu
// hem doğrudan hem unstable_cache() içinden çağrılıyor
import { unstable_cache } from 'next/cache';
async function getPrices() {
'use cache';
// ... root param'a (ör. locale) bağlı veri erişimi
}
const getPricesLegacy = unstable_cache(getPrices, ['prices']);
Tek bir önbellek mekanizmasında kalın. Ek bir savunma katmanı olarak, anahtara girmesini istediğiniz değeri fonksiyona açıkça argüman olarak geçmek de iyi bir alışkanlık; 'use cache' fonksiyonlarında argümanlar önbellek anahtarının parçasıdır:
async function getPrices(locale: string) {
'use cache';
return fetchPrices(locale);
}
2. İç içe 'use cache' ve gecikmeli stream (GHSA-vc7v)
Cache Components açıkken bir dış 'use cache' fonksiyonu, içinde çağırdığı başka bir 'use cache' fonksiyonunun root param bağımlılığını kaçırabiliyor.2 Bunun için iç fonksiyonun next/root-params ile root param okuması ve içinde hâlâ bekleyen promise'ler bulunan bir değer döndürmesi gerekiyor; örneğin hemen hazır olan veriyle birlikte yavaş gelen veriyi aynı nesnede döndürmek.
React Flight, hazır olan kısmı iç giriş root param bağımlılıklarını yayımlamadan önce dış fonksiyona iletiyor. Dış fonksiyon bitip girişini root param içermeyen bir anahtarla kaydediyor ve bu giriş tüm değerler için yeniden kullanılıyor. Bildirime göre bu şekilde yazılan girişler iç önbelleklerin tag invalidation ve ömür ayarlarını da yok sayabiliyor. Sızan değeri saldırgan seçemiyor; hangi değerin sunulacağını yalnızca girişi ilk kimin yazdığı belirliyor.
Bu açık, Ekim'de 16.3.8 ile kapatılan GHSA-h694'ün bir varyantı. Önceki düzeltme bu yolu kapsamıyordu, bu yüzden 16.3.8'e geçmiş olmanız yeterli değil.
3. Binary argümanlarla aynı önbellek anahtarı (GHSA-rhh4)
'use cache' fonksiyonlarına Uint8Array veya Blob gibi binary argümanlar geçen App Router uygulamalarında, farklı argümanlar aynı önbellek anahtarını üretebiliyor.3 Sonuç olarak bir kullanıcının önbelleğe alınmış verisi başka bir kullanıcıya dönebiliyor ya da önbellek zehirlenebiliyor.
Bildirimde bir geçici çözüm yer almıyor; çözüm yükseltmek. Yükseltene kadar benim önerim, bu fonksiyonlara binary veri yerine kararlı bir metin kimliği (ör. dosyanın hash'i veya kayıt kimliği) geçmek.
4. Paylaşılan fallback shell zehirlenmesi (GHSA-vvgp)
next start ile self-hosted çalışan, cacheComponents: true ile derlenmiş ama Partial Prefetching kapalı olan uygulamalarda tek bir kimlik doğrulamasız GET isteği, bir route ailesinin paylaştığı fallback shell önbellek girişini zehirleyebiliyor.4 Uygulamaya göre sonuç ya her URL'de kalıcı bir 404 (sunucu yeniden başlasa bile, log'a hata düşmeden) ya da sunucu tarafında saldırganın verdiği parametre değerinin görünmesi oluyor. Bildirime göre ikinci durumda betik veya HTML enjeksiyonu mümkün değil ve veri sızmıyor; istemci tarafındaki JavaScript hydration sırasında değeri düzeltiyor.
Bildirimde beş ön koşul sayılıyor: Cache Components açık ve Partial Prefetching kapalı, self-hosted next start, build sırasında üretilmemiş bir değerle istenen ve generateStaticParams kullanan bir dinamik route, altında hiç prerender edilemeyen en az iki parametre ve bloklayan bir fallback shell. Resmi geçici çözüm next.config içinde Partial Prefetching'i açmak:
// next.config.ts — GHSA-vvgp için bildirimdeki geçici çözüm
const nextConfig = {
cacheComponents: true,
partialPrefetching: true,
};
export default nextConfig;
15.x'i de etkileyen üç açık
Bu üç açık 15.x hattında da bulunduğu için 16'ya geçmemiş projeleri de doğrudan ilgilendiriyor.
5. Upstream yanıtını aynen döndürmek ve yanıt karışması (GHSA-pc58)
Fetch ile aldığı upstream yanıtını hiç değiştirmeden döndüren self-hosted uygulamalar (App Router route handler'ları ve fetch cache), beyan ettiği çerçeve bilgisi gövdeyle uyuşmayan bir yanıt üretebiliyor.5 Uygulama, yanıtların sıraya alınmasına (pipelining) izin veren bir HTTP/1.1 ters vekilin (reverse proxy) arkasındaysa, özel hazırlanmış bir upstream yanıtı istemciler arasındaki yanıtları kaydırabiliyor. Bu da yanıt enjeksiyonuna ve başka istemcilerin yanıtlarının ifşasına yol açıyor.
// Riskli kalıp: upstream yanıtı olduğu gibi döndürmek
export async function GET() {
return fetch('https://api.example.com/rapor');
}
Bu açık 15.5.28 ve öncesindeki tüm sürümleri alt sınır olmadan kapsıyor. Yükseltene kadar benim önerim, yanıtı aynen geçirmek yerine gövdeyi okuyup yeni bir Response oluşturmak; böylece çerçeve bilgisini Next.js yeniden hesaplar.
6. Görsel optimizasyonunda SVG reddi atlatma (GHSA-7qx7)
Self-hosted kurulumlarda /_next/image, SVG desteği dangerouslyAllowSVG: false ile kapalıyken (varsayılan ayar budur) bile saldırganın gönderdiği bir SVG'yi işleyebiliyor.6 Uygulamanın kapalı tutmayı amaçladığı SVG ayrıştırıcıya erişilmesi, hizmet dışı bırakma ve SVG çözücü açıklarına karşı yüzeyi büyütüyor. Varsayılan ayarlarla self-hosted çalışan ve next/image kullanan çoğu proje bu koşulu karşılıyor.
7. Edge runtime'da HttpOnly çerez ifşası (GHSA-f3mh)
Edge runtime üzerinde çalışan route'larda (App Router route handler'ları ve Pages Router Edge API route'ları) NextResponse ile çerez yazıldığında, Next.js herkese açık yanıta dahili x-middleware-set-cookie başlığını da ekliyor ve çerez değerini özellikleriyle birlikte tekrarlıyor.7 Bu da oturum belirteci gibi HttpOnly çerezlerin aynı origin'de çalışan JavaScript tarafından okunabilmesine yol açıyor. HttpOnly bayrağının asıl amacı tam olarak bunu engellemek olduğu için, Edge'de oturum çerezi yazan uygulamalar için bu açık önemli.
Ekim yamalarını atladıysanız
Kasım güncellemesi, Ekim'deki iki yama turunun üzerine geliyor. 15.5.28 ve 16.4.1'den eski bir sürümdeyseniz şu açıklar da sizi ilgilendiriyor:10
- Kritik — Görsel optimizasyonunda uzaktan kod çalıştırma (GHSA-2464): Görsel optimizasyonunda kullanılan bir üst bağımlılıktaki bellek hatası, Next.js glibc tabanlı Linux'ta çalışırken uzaktan kod çalıştırmaya yol açabiliyor. Bildirimdeki geçici çözüm, Next.js'in kullandığı
sharpsürümünün en az 0.35.5 olmasını sağlamak. - Kritik — Typed array döndüren 'use cache' fonksiyonları (GHSA-673q): 16.0.0 – 16.4.0 aralığında, birden çok typed array döndüren
'use cache'fonksiyonları uzaktan kod çalıştırmaya açık. Geçici çözüm yok. - Yüksek — Server Actions ile hizmet dışı bırakma (GHSA-p3m5): En az bir Server Action içeren App Router uygulamalarında özel hazırlanmış istekler aşırı CPU kullanımına yol açabiliyor.
15.5.29 ve 16.4.5 bu düzeltmelerin hepsini içeriyor; tek bir yükseltmeyle ikisini birden kapatırsınız.
Etkileniyor muyum? Beş dakikalık kontrol
Bildirimlerdeki koşulları kendi kodunuzda aramak birkaç komut sürüyor. Proje kökünde çalıştırın:
# Hangi Next.js ve sharp sürümü kurulu?
npm ls next sharp
# 'use cache' ve unstable_cache birlikte kullanılıyor mu?
grep -rn --include='*.ts' --include='*.tsx' -E "['\"]use cache['\"]" src app
grep -rn --include='*.ts' --include='*.tsx' "unstable_cache" src app
# Edge runtime'da çalışan route var mı?
grep -rn --include='*.ts' --include='*.tsx' -E "runtime\s*=\s*['\"]edge['\"]" src app
# Cache Components, Partial Prefetching ve SVG ayarları
grep -n -E "cacheComponents|partialPrefetching|dangerouslyAllowSVG" next.config.*
Bu blogdaki kontrol
Aynı kontrolü bu blogun çalıştığı projede de yaptım. Proje Next.js 15.5 App Router ile yazılmış, Docker içinde (Alpine) self-hosted çalışıyor ve görselleri next/image ile sunuyor:
| Bildirim | Sonuç |
|---|---|
| GHSA-7qx7 (SVG reddi atlatma) | Etkileniyordu: self-hosted, /_next/image kullanılıyor, SVG varsayılan olarak kapalı |
| GHSA-f3mh (HttpOnly çerez) | Etkilenmiyor: Edge runtime route'u yok |
| GHSA-pc58 (yanıt karışması) | Etkilenmiyor: upstream yanıtı aynen döndüren route yok |
'use cache' bildirimleri | Etkilenmiyor: yalnızca 16.x hattında |
| Ekim — sharp (GHSA-2464) | sharp 0.35.4 kuruluydu; bildirim glibc tabanlı Linux'u işaret ettiği için Alpine (musl) imajında istismar edilebilirliği düşük, yine de 0.35.5'in altındaydı |
| Ekim — Server Actions (GHSA-p3m5) | Etkilenmiyor: Server Action yok |
Sonuç olarak proje 15.5.29'a yükseltildi; bu sürüm sharp'ı da 0.35.5'e taşıdı. Ders: "biz o özelliği kullanmıyoruz" demeden önce koşulları tek tek kontrol etmek gerekiyor. Varsayılan ayarlar bile bir koşulu karşılayabiliyor.
Yükseltme adımları ve geçici çözümler
# 16.x hattı
npm install next@16.4.6
# 15.x hattı
npm install next@15.5.29
# pnpm veya yarn kullanıyorsanız
pnpm add next@15.5.29
yarn add next@15.5.29
# Doğrulama
npm ls next sharp
Pratikte karşılaştığım bir tuzak: eslint-config-next'i aynı komuta eklemeyin. Projeniz 15.x üzerinde çalışıp lint kuralları için 16.x yapılandırmasını kullanıyorsa, komut bu paketi de geriye düşürür ve kilit dosyasında gereksiz bir değişiklik yaratır. Sadece next'i yükseltin ve package.json farkında yalnızca o satırın değiştiğini kontrol edin.
Docker ile çalışıyorsanız imajı yeniden derlemeyi unutmayın; kilit dosyası güncellenmeden ya da imaj yeniden derlenmeden yükseltme canlıya yansımaz:
docker compose up -d --build
Hemen yükseltemiyorsanız bildirimlerde iki resmi geçici çözüm var: GHSA-mfr8 için 'use cache' fonksiyonunu unstable_cache() içinden çağırmayı bırakmak, GHSA-vvgp için partialPrefetching: true ayarı. Diğer beş açık için bildirimlerde bir geçici çözüm yer almıyor.
Yamayı testlerle doğrulamak
Güvenlik güncellemesi bir kez yapılıp unutulacak bir iş değil. Bir sonraki bağımlılık güncellemesinde sürümün yanlışlıkla geri düşmediğinden ve önbelleğin kullanıcılar arasında karışmadığından emin olmak için testler yazmak gerekiyor.
1. CI'da sürüm bekçisi
Bu küçük betik, kurulu Next.js sürümü yamalı sürümün altındaysa CI adımını başarısız yapıyor:
// scripts/check-next-version.mjs
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
const { version } = require('next/package.json');
// Kasım 2026 güvenlik yamalarını içeren en düşük sürümler
const minimums = { 15: [15, 5, 29], 16: [16, 4, 5] };
const current = version.split('-')[0].split('.').map(Number);
const compare = (a, b) => a[0] - b[0] || a[1] - b[1] || a[2] - b[2];
const [major] = current;
if (major > 16) {
console.log(`next@${version}: kontrol edilen hatlardan daha yeni.`);
process.exit(0);
}
const minimum = minimums[major];
if (!minimum || compare(current, minimum) < 0) {
console.error(`next@${version} Kasım 2026 güvenlik yamalarını içermiyor.`);
process.exit(1);
}
console.log(`next@${version} yamalı sürümde.`);
package.json içine "check:next": "node scripts/check-next-version.mjs" ekleyip pipeline'da build adımından önce çalıştırmanız yeterli.
2. Önbellek izolasyon testi
Root param sızıntılarını yakalamanın en güvenilir yolu, önbelleğe alınan verinin içine root param değerini de koymak ve sayfada bir işaretçi olarak göstermek. Örneğin getPrices(locale) fonksiyonu { locale, items } döndürür, sayfa da data-locale={data.locale} basar. Yanlış giriş sunulursa işaretçi istenen dille uyuşmaz:
// tests/security/cache-isolation.spec.ts
import { test, expect } from '@playwright/test';
const locales = ['tr', 'en', 'de'] as const;
test('önbellek sonuçları dil değerleri arasında karışmıyor', async ({ request }) => {
// Sunucu yeni başlatıldıktan hemen sonra gönderilen eş zamanlı istekler,
// cold start sırasındaki yarış penceresini zorlar.
const responses = await Promise.all(
locales.map((locale) => request.get(`/${locale}/fiyatlar`)),
);
for (const [index, response] of responses.entries()) {
expect(response.ok()).toBeTruthy();
const html = await response.text();
expect(html).toContain(`data-locale="${locales[index]}"`);
}
});
Testin anlamlı olması için her koşuda temiz bir süreçle başlamak gerekiyor. Playwright'ın webServer ayarıyla uygulamayı test öncesinde derleyip başlatabilir, hazır bir sunucuyu yeniden kullanmayı kapatabilirsiniz:
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: { baseURL: 'http://localhost:3000' },
webServer: {
command: 'npm run build && npm run start',
url: 'http://localhost:3000',
reuseExistingServer: false,
timeout: 180_000,
},
});
3. Çerez başlığı testi
Edge runtime'da çerez yazan bir route'unuz varsa, yükseltme sonrasında dahili başlığın yanıtta görünmediğini doğrulayın:
import { test, expect } from '@playwright/test';
test('Edge route yanıtı çerezi dahili başlıkta tekrarlamıyor', async ({ request }) => {
const response = await request.post('/api/login', {
data: { email: process.env.TEST_USER_EMAIL, password: process.env.TEST_USER_PASSWORD },
});
expect(response.ok()).toBeTruthy();
expect(response.headers()['x-middleware-set-cookie']).toBeUndefined();
});
Bu testler yamanın kendisini değil, uygulamanızın güvenlik açısından beklenen davranışını doğruluyor. Bu yüzden bir sonraki Next.js sürümünde benzer bir gerileme olursa da işe yarıyorlar.
Sıkça Sorulan Sorular
Vercel'de barındırıyorum, yine de yükseltmem gerekiyor mu?
'use cache' sızıntıları ve Edge'deki çerez ifşası bildirimlerinde barındırma yerine bağlı bir istisna belirtilmiyor. En güvenli yol, hangi platformda olursanız olun yamalı sürüme geçmek.Next.js 14 kullanıyorum, ne yapmalıyım?
'use cache' kullanmıyorum, 16.x'te yine de risk var mı?
'use cache' kullanımından bağımsız. Ayrıca 16.4.1 öncesindeyseniz Ekim'deki kritik açıklar da geçerli.Yükseltemiyorsam geçici bir çözüm var mı?
'use cache' fonksiyonunu unstable_cache() içinden çağırmamak, GHSA-vvgp için partialPrefetching: true ayarı. Diğer açıklar için resmi yol yükseltmek.16.4.6'ya geçmem gerekiyor mu, 16.4.5 yeterli mi?
Kaynakça
İçerikte üst simge ile belirtilen kaynak numaraları, aşağıdaki referanslarla eşleşmektedir.
- vercel/next.js — GHSA-mfr8-8qww-v76h: Information disclosure across root params when a 'use cache' function is called through unstable_cache()
- vercel/next.js — GHSA-vc7v-qv4w-wrv8: Cache leak across root param values in nested 'use cache' functions
- vercel/next.js — GHSA-rhh4-g77r-r9qj: Cross-user cache disclosure and poisoning in use cache with binary arguments
- vercel/next.js — GHSA-vvgp-ww4w-46vf: Cache poisoning of shared fallback shells in Cache Components
- vercel/next.js — GHSA-pc58-hwjq-p385: Cross-client response injection and disclosure in self-hosted applications
- vercel/next.js — GHSA-7qx7-33qx-rqx2: SVG rejection bypass in Next.js image optimization
- vercel/next.js — GHSA-f3mh-rxg3-f5g2: HttpOnly cookie exposure on Edge runtime routes
- vercel/next.js — v16.4.5 sürüm notları (3 Kasım 2026)
- vercel/next.js — v15.5.29 sürüm notları (3 Kasım 2026)
- vercel/next.js — GHSA-2464-fhr4-w9xw: Unauthenticated Remote Code Execution in Image Optimization API (Ekim 2026)


