Kimsenin Konuşmak İstemediği AI API Key Sızıntısı Pattern’i

AI API key sızıntıları 2026’da neden arttı: Gemini public Google key’lerini değerli kıldı, NEXT_PUBLIC_ secret’ları sızdırıyor; çözüm bir server route.

Neredeyse hiçbir zaman dikkatsiz bir geliştirici değil. Sessizce yer değiştiren bir sınır.

Bir AI API key’ini kullanmanın yanlış ve doğru yolunu gösteren siyah-beyaz karşılaştırma diyagramı; solda key client-side kodda açıkta, sağda sunucuda tutuluyor.

LinkedIn’de bir kurucu, geçen hafta internette dolaşan AI videolarının kendi hesabında üretildiğini fark etti. Bir Gemini API key’i sızmıştı. Fark ettiğinde aylık harcama limiti neredeyse dolmuştu.

Paylaşımının altındaki yanıtlar benzer hikâyelerle doluydu.

Meksika’daki bir ekip, normalde aylık 180 dolar olan harcamalarına karşılık 48 saatte 82.000 dolarlık bir faturayla uyandı. Tek başına çalışan bir geliştirici 10 dolarlık bir bütçe uyarısıyla yattı ve Google Cloud’a 25.672 dolar borçlu olarak uyandı. Farklı ülkeler, farklı stack’ler, aynı şablon.

Şu anda r/googlecloud’da gezinirseniz bunların ardı arkası kesilmeden geldiğini görürsünüz. Her birinin altındaki yorumlar aynı seyri izler: önce şok, sonra bu nasıl oldu, ardından faturalandırma destek ekibiyle uzun bir mücadele.

İlginç olan soru “geliştiriciler neden dikkatsiz davranıyor” değil.

Asıl soru şu: Neredeyse on yıl boyunca büyük ölçüde sorunsuz giden bu hata türü neden 2026’da patlama yaşıyor?

Yer değiştiren sınır

On yılı aşkın bir süre boyunca Google, geliştiricilere bazı API key’lerin client-side koda gömülmesinin güvenli olduğunu söyledi. Maps key’leri, Firebase config’i, herkese açık analytics. Model basitti: bu kimlik bilgileri kullanıcıyı değil uygulamayı doğruluyordu ve siz de onları referrer kısıtlamaları ve kotalarla sınırlıyordunuz. Onları JavaScript’inize koymak sadece serbest değildi — dokümante edilmiş yol buydu.

Sonra Gemini geldi.

Truffle Security’deki güvenlik araştırmacıları, başlığı tüm durumu özetleyen bir yazı yayımladı: Google API key’leri sır değildi. Ama sonra Gemini kuralları değiştirdi. Açıkça söylemek gerekirse: Google’ın yıllarca açığa çıkarmanın güvenli olduğunu söylediği aynı key formatları artık Gemini’de kimlik doğrulayabiliyor ve hesabınızda para harcamaya başlayabiliyor.

Key’lerde hiçbir şey değişmedi. Sınır değişti.

Mühendisler için önemli olan kısım bu. 2022’de doğru bir şekilde “public” olarak sınıflandırılan bir kimlik bilgisi — production koduna gömülmüş, repo’lara commit edilmiş, tasarım gereği DevTools üzerinden görünür olan — eriştiği yüzey sessizce genişletildiği için 2026’da yüksek değerli bir secret haline geldi.

Kimseye e-posta gelmedi.

Bu hikâyelerin bu kadar çoğunun geliştiricinin “bariz bir hata bulamadık” demesiyle bitmesinin sebebi de bu. Yalan söylemiyorlar. Hata yapısaldı; sızıntıdan yıllar önce, o zaman var olan dokümantasyonu takip eden biri tarafından yapılmıştı.

Diğer yarısı: yanlış yapmanıza yardım eden bir framework

Bulut tarafı kimseye haber vermeden yer değiştirdi. Framework tarafında ise daha sessiz ama bağlantılı bir tuzak var.

Next.js’te NEXT_PUBLIC_ önekiyle başlayan her environment variable, tasarım gereği tarayıcıya gönderilen JavaScript bundle’ına gömülür. Resmi dokümantasyon bu konuda açık. Bu "public ama gizli" değil. Bu "bu değer client’ta olacak" demek.

Önek bir kolaylık, güvenlik özelliği değil. Frontend kodunun Google Maps client key’i ya da Stripe publishable key’i gibi public değerleri okuyabilmesi için var. Bir secret’ı gizlemenin tam tersini yapar — değerin her ziyaretçiye gönderileceğini ilan eder.

Ama gerçek codebase’lerde sürekli gördüğüm şey şu:

// client component
await fetch("https://api.provider.com/v1/chat", {
headers: {
Authorization: `Bearer ${process.env.NEXT_PUBLIC_AI_KEY}`
}
})

Bu çalışan bir istek. Derleniyor. Çalışıyor. AI sağlayıcısından gerçek bir yanıt dönüyor.

Aynı zamanda key’i DevTools’u açan herkese sızdırıyor.

Bu pattern’in artık her yerde olmasının sebebi, AI özelliklerinin artık her yerde olmasının sebebiyle aynı: model bu snippet’i üç saniyede doğru şekilde üretebiliyor. Her quickstart rehberindeki koda benziyor. Lokalde ilk denemede çalışıyor.

Eksik olan tek şey mimari soru: bu kodun nerede çalışmasına izin var?

Çözüm sıkıcı, mesele de tam olarak bu

Daha güvenli pattern çok uzun zamandır ortada. Yeni değil, zekice değil ve kurulacak bir kütüphane de yok.

Client component
↓
Route Handler ← your server-side code
↓
Server reads the secret from a non-NEXT_PUBLIC_ env var
↓
Provider call happens server-side
↓
Client only gets the response

Next.js terimleriyle: AI sağlayıcısına yapılan fetch bir route.ts’de ya da bir server action’da yaşar. Key, NEXT_PUBLIC_ öneki olmayan normal bir env var’dan okunur. Tarayıcı onu asla görmez.

Gerçek kod şöyle görünüyor. Sunucu tarafı:

// app/api/chat/route.ts
import { NextResponse } from "next/server"
export async function POST(req: Request) {
const body = await req.json()
  const res = await fetch("https://api.provider.com/v1/chat", {
method: "POST",
headers: {
// Read from a server-only env var — no NEXT_PUBLIC_ prefix.
Authorization: `Bearer ${process.env.AI_PROVIDER_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify(body)
})
  const data = await res.json()
return NextResponse.json(data)
}

Client tarafı:

// client component
const res = await fetch("/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ prompt })
})

Tüm çözüm bu. Tek bir dolaylama katmanı. Key asla tarayıcıya ulaşmaz. Üstüne bir de artık rate limiting, istek loglama, kullanıcı kimlik doğrulaması ve kullanıcı başına harcama limitleri ekleyebileceğiniz bir yeriniz olur — client doğrudan sağlayıcıyla konuşurken bunların hiçbirini yapamazsınız.

AI asistanları bunu neden iyileştirmiyor, kötüleştiriyor

Burada dikkatli olmak istiyorum, çünkü bu kulağa iddialı bir görüş gibi gelen ama aslında en önemli olan kısım.

Sorun model değil. Model, isterseniz sunucu tarafı versiyonu kusursuz yazabilir. Sorun şu ki model, onu isterseniz client tarafı versiyonu da kusursuz yazar ve iki versiyon, gece 11’de bir özelliği yayına almaya çalışan yorgun bir geliştiriciye neredeyse aynı görünür.

// looks fine
await fetch("https://api.provider.com/v1/chat", {
headers: { Authorization: `Bearer ${process.env.NEXT_PUBLIC_AI_KEY}` }
})
// also looks fine
await fetch("/api/chat", {
method: "POST",
body: JSON.stringify({ prompt })
})

Aynı şekil. Aynı satır sayısı. İlki key’inizi her ziyaretçiye gönderir. İkincisi göndermez.

Model hangisinin doğru olduğunu size söyleyemez, çünkü doğruluk dosyanın nerede durduğuna, framework’ün onu hangi runtime için derleyeceğine ve güven sınırınızın ne olduğuna bağlıdır. Bunların hiçbiri prompt’ta yok. Bunların hiçbiri snippet’te yok.

AI asistanları fikirden çalışan koda geçen süreyi kısaltır. Mimari üzerine düşünmek için gereken süreyi kısaltmaz. Hatta aradaki açığı büyütür — çünkü artık çalışan kod, onun olması gerekip gerekmediğini düşünmeye fırsat bulamadan ekranınıza düşüyor.

AI kod yazmada daha iyi hale geldikçe değeri azalmayan, aksine artan asıl mühendislik becerisi bu: modelin sizin adınıza hangi soruları sormadığını bilmek.

AI özelliklerini yayına almadan önce kısa bir kontrol listesi

Bu ay bir web uygulamasına AI sağlayıcısı ekliyorsanız, şunlardan geçin:

  • API key, client bundle’ına giren herhangi bir dosyada mı? Uygulamayı build edin ve çıktıda grep ile arayın. Key oradaysa, public’tir.
  • Key’in başında NEXT_PUBLIC_, VITE_, REACT_APP_ ya da onu tarayıcıya açan başka bir önek var mı? Varsa, zaten sızmış kabul edin.
  • Sağlayıcı çağrısı doğrudan tarayıcıdan mı yapılıyor? Öyleyse onu bir route handler’ın arkasına taşıyın.
  • Sağlayıcı hesabında, proje bütçenizden ayrı bir harcama limiti tanımlı mı? Sağlayıcı tarafındaki limitler kanamayı faturalandırma uyarılarından daha hızlı durdurur.
  • Sadece sağlayıcının değil, sizin endpoint’inizde de rate limit var mı? Key sunucu tarafında kalsa bile sızmış bir endpoint de bir sorundur.
  • Dev ve prod’da aynı key’i mi kullanıyorsunuz? Ayırın — dev key’i eninde sonunda bir ekran görüntüsüne ya da public bir repo’ya düşecektir.

Bunların hiçbiri yeni değil. Özellik gece 11’de yayına alındığında hepsi atlanıyor.

Suç değil, sınır

Bu sızıntı hikâyelerinin her birinde beni en çok rahatsız eden şey, verilen tepkilerin tonu. Yorum bölümleri “ne yaptığını bilmeyince olacağı bu” diyen insanlarla doluyor; bu hem kaba hem de yanlış. Bu başlıklardaki geliştiricilerin çoğu yetkin. Bazıları senior. Okudukları zaman doğru olan dokümantasyonu takip ettiler.

Sınır yer değiştirdi. Dokümantasyonun yetişmesi zaman aldı. Framework, adının çağrıştırdığı anlama gelmeyen bir kolaylık öneki sundu. AI asistanı lokalde çalışan bir kod yazdı. Ve fatura, bunların hiçbiri görünür hale gelmeden geldi.

Ders “daha dikkatli ol” değil. Ders şu: “bu kod nerede çalışıyor ve neye erişimi var” sorusu, toolchain’in sizin yerinize soracağı bir soru değil. Bu sizin sorumluluğunuzdaki kısım.

Artık bir ürüne herhangi bir AI API’ı eklemeden önce ilk olarak tek bir şeyi kontrol ediyorum:

Bu key hiç tarayıcıya ulaşabilir mi?

Cevap evetse, mimari zaten yanlıştır.

Bu AI sağlayıcı faturası hikâyelerinden biriyle karşılaştınız mı — ister kendi başınızdan geçsin, ister bir arkadaşınızın yaşadığına tanık olun? Pattern’leri topluyorum. Projenin adını vermeden paylaşabileceğiniz bir hikâyeniz varsa yorum bırakın.

AI-native full stack mühendislik, production sistemleri ve model ile altyapı arasındaki sınır üzerine yazıyorum. İlginizi çekiyorsa takip edin.

Bu yazı İngilizce aslından Türkçeye çevrilmiştir.

İlk yayın: Medium ↗