Structured Outputs · 19-c06
26 Haziran 2026 · Güvenlik okuması
Bir structured output'un schema validation'ı geçmesi, onun güvenli olduğu anlamına gelmez. Doğru şekil (valid shape) pekala kötü niyet (invalid intent) taşıyabilir: enum'a sığan bir değer, JSON'a sığan bir tool argümanı, tipi doğru ama içeriği zehirli bir string. Validator yolu değil tipi denetler; değeri ise sonuna kadar untrusted saymak gerekir.
- Yanılgı
- valid şekil = güvenli
- Gerçek
- şekil ≠ niyet
- Yüzey
- value · tool arg · sink
- Kural
- tip doğrula, değere güvenme
Bu yazıdaki kavramlar
- structured output
- schema validation
- prompt injection
- tool args
- downstream sink
- allow-list
- control plane
structured output (modelin önceden verilen bir JSON Schema'ya uyan çıktı üretmesi) son birkaç yılın en pratik ilerlemelerinden biri. Eksik anahtar, geçersiz enum, parse edilemeyen JSON gibi şekil hataları büyük ölçüde ortadan kalkıyor. Ama burada sessiz bir varsayım var: şekil doğruysa içerik de güvenlidir. Bu varsayım yanlış.
Bu yazıda dört ayrı saldırı yüzeyini sırayla açıyorum: alan değerlerine (field value) gizlenmiş injection, schema'nın güvenlik sanılması, tehlikeli tool argümanları ve asıl saldırı yüzeyi olan downstream parser. Şemalar kendi başına sürekli oynuyor; her biri tek bir fikri gösteriyor: geçerli bir kabuk, geçersiz bir niyeti taşıyabilir.
Şekil geçerli, niyet geçerli değil
Bir structured output objesi düşün: bütün alanlar dolu, enum değerleri tanımlı, JSON parse ediliyor. schema validation yeşil yanıyor. Ama bu yeşil ışık yalnızca şeklin doğru olduğunu söyler. İçerideki string alanın bir HTML payload'ı, bir SQL parçası, bir dosya yolu ya da bir komut taşıyıp taşımadığı hakkında hiçbir şey söylemez.
OWASP'ın LLM05 Improper Output Handling maddesi tam da bunu işaret eder: validation veya sanitization yapılmadan downstream'e (browser, veritabanı, dosya sistemi, template) geçirilen model çıktısı XSS, SQL injection, SSRF, path traversal ya da RCE'ye dönüşebilir. Şekil kontrolü bu sınıftan tek bir riski bile kapatmaz.
Burada sink dediğim şey, değerin gerçekten kullanıldığı, yani yorumlanıp bir etkiye dönüştüğü son noktadır: bir veritabanı sorgusu, bir HTML sayfası, bir shell komutu, bir dosya yolu ya da bir tool çağrısı. Downstream ise modelin çıktısını sonradan tüketen bileşenler. Yani downstream sink, structured output'un değerlerine göre gerçekten hareket eden alt sistemdir.
Aşağıda aynı obje iki kez okunuyor. Soldaki validator yalnızca tipe bakıyor ve geçiriyor; sağdaki sink ise değeri yorumladığı an tehlike patlıyor. Validator önleme değil, otopsidir: olaydan sonra şekli teyit eder, niyeti durdurmaz.
field: note (string)
şekil: geçerli string
Schema bir kontrat, güvenlik sınırı değil
OpenAI'ın structured outputs kılavuzu schema'nın ne olduğunu net koyar: strict: true ile çıktının verilen JSON Schema'ya uyacağını garanti eder. Ama aynı kılavuz, parse etmeden önce ayrı durumların ele alınması gerektiğini söyler: bir refusal (modelin güvenlik gereği reddi) istenen şemayla eşleşmeyebilir; uzunluk limiti ya da content filter çıktıyı yarıda kesebilir.
Bu yüzden schema bir interface kontratıdır: çıktının biçimini garanti eder, içeriğin güvenli ya da yetkili olduğunu garanti etmez. Refusal'ı, kesilmiş yanıtı ya da filtrelenmiş içeriği körü körüne typed parser'a vermek, güvenlik sinyalini veriye karıştırmak demektir. Önce hangi durumda olduğunu anla, sonra parse et.
Aşağıda dört çıktı durumu sırayla geliyor: temiz parse, refusal, uzunluk kesintisi, content filter. Yalnızca ilki typed parser'a güvenle akar; diğer üçü ayrı dallara gitmeli. schema hepsinin şeklini değil, yalnızca ilkinin niyetini doğrular.
parse etmeden önce durumu ayırt et, sinyali veriye karıştırma
Injection alan değerlerinin içinde
prompt injection (modele dışarıdan verilen içeriğin davranışını ele geçirmesi) yalnızca sohbet kutusunda olmaz. Greshake ve arkadaşlarının indirect prompt injection çalışması gösterir ki: bir web sayfasına, bir e-postaya ya da retrieval ile çekilen bir dokümana gizlenmiş talimatlar, kullanıcı hiç farkına varmadan modeli yönlendirebilir. O içerik sonra bir structured output alanına sızar.
Sonuç şudur: sözdizimsel olarak kusursuz bir string alanı, operasyonel bir talimat, bir exfiltration payload'ı, HTML/Markdown, bir SQL parçası ya da bir tool argümanı taşıyabilir. NCSC'nin deyimiyle LLM 'doğası gereği kafası karışabilen bir vekildir' (confusable deputy): altta tipli veri ile komut ayrımı yoktur, yalnızca sıradaki token vardır.
Aşağıda zehirli bir değer modelden çıkıp validator'dan geçiyor (yeşil, çünkü tip doğru) ve farklı downstream sink'lerden birine ulaşıyor. Tehlike validator'da değil, sink'te canlanıyor: HTML render, SQL builder, dosya yolu. Her sink kendi escaping'ini istiyor.
tip doğru · geçti
validator değeri geçirir; her sink kendi escaping'ini ister
İki kapı: şekil ve niyet
Çözüm şekil kontrolünü atmak değil, üstüne bir niyet kontrolü koymaktır. İlk kapı schema validation: tip, enum, gerekli alanlar. İkinci kapı ise allow-list ve policy: bu değer izin verilen kümede mi, bu origin için yetkili mi, bu eylem onaylı mı? NCSC ve OWASP aynı şeyi söyler: deterministik, modelin dışında duran kontroller şart.
Kritik nokta şu: ikinci kapı LLM'in içinde olamaz, çünkü model tipli veri ile komutu ayıramaz. Yetkilendiren mekanizma modelin dışında, verinin origin'ine ve otoritesine bağlı olmalıdır. structured output talimatları type-safe gösterir; bu görsel güven yanıltıcıdır.
Aşağıda iki obje aynı schema'dan geçiyor. İkisinin de şekli doğru, ikisi de ilk kapıyı yeşil geçiyor. İkinci kapı (allow-list) birini geçiriyor, diğerinin değeri izin listesinde olmadığı için kırmızıya çeviriyor. Şekil eşit, niyet farklı.
Tehlikeli tool argümanları
Tool calling'de model bir fonksiyonu seçer ve argümanlarını doldurur. Bu argümanlar bir schema'ya uyar, ama uyması güvenli oldukları anlamına gelmez. Greshake çalışması tam da bunu vurgular: tool/API entegrasyonu prompt injection'ı büyütür, çünkü saldırgan modelin hangi API'yi nasıl çağıracağını etkileyebilir. path alanı /etc altını gösterebilir, amount beklenmedik olabilir, url bir exfiltration adresi olabilir.
Buradaki gerçek soru argümanın şemaya uyup uymadığı değil, seçilen tool'un ve argümanlarının veri origin'i, kullanıcı ve istenen eylem için yetkili olup olmadığıdır. OWASP yüksek riskli eylemler için insan onayı (human approval) ve least privilege önerir; NCSC ise modelin işlediği verinin otoritesi kadar ayrıcalık verilmesini söyler.
Aşağıda model bir tool çağrısı üretiyor, argümanlar schema'ya uyuyor (yeşil). Ama execution'dan önce deterministik bir policy check var: argüman izinli kapsamın dışındaysa çağrı çalıştırılmadan durduruluyor. schema'yı geçmek execution iznini vermez.
Tool seçimini ele geçirmek
Risk yalnızca argümanlarda değil, hangi tool'un seçildiğinde de var. ToolHijacker çalışması (Shi ve arkadaşları) gösterir ki: tool kütüphanesine sokulan kötü niyetli bir tool dokümanı, retrieval ve selection aşamasını saptırabilir. Model sonunda yalnızca seçilen tool adını parse edilebilir bir JSON olarak verse bile, o seçim zaten zehirlenmiş bir bağlamdan çıkar.
Yani tool açıklamaları ve metadata, modelin yönlendirmesi üzerinde çalıştırılabilir bir etkidir. Structured tool-choice çıktısı, seçilen tool'un güvenli, yetkili ya da doğru kapsamlı olduğunu garanti etmez. Çalışma StruQ, SecAlign, perplexity gibi savunmaları test eder ve hepsinin tek başına yetersiz kaldığını bulur.
Aşağıda bir tool registry'si var. Zehirli bir tool dokümanı (kırmızı) selection puanını şişirip seçimi kendine çekiyor; structured çıktı yine geçerli JSON. Doğru savunma: registry'yi bir supply-chain varlığı gibi gör, provenance doğrula, imzala/pin'le, untrusted eklentileri ayrı tut.
registry'yi imzala · provenance · pin
Schema'nın kendisi bir kontrol düzlemi
Şimdiye kadar değer veriydi (data plane). Ama schema'nın kendisi de bir saldırı yüzeyi olabilir. Zhang ve arkadaşlarının çalışması structured output'a özgü bir control plane riskini tanımlar: constrained decoding için kullanılan grammar/JSON Schema üretimi yönlendirir. Kötü niyet görünür prompt'a değil, schema'nın kendisine yerleştirilirse, klasik input/output savunmaları bunu kaçırır.
Çalışmadaki EnumAttack kötü içeriği enum değerlerine saklar; DictAttack ise payload parçalarını prompt ile grammar arasında böler. Rapor edilen attack success oranları tedirgin edici biçimde yüksek. Çıkarım nettir: kullanıcı, tenant, plugin ya da veri pipeline'ı tarafından üretilen schema güvenilir değildir.
Aşağıda bir enum alanı, görünüşte masum seçenekler arasında zehirli bir değer taşıyor. Decoder schema'ya uymak zorunda olduğu için bu değeri üretebilir; data plane savunması yalnızca veriye bakar ve control plane'i kaçırır. Schema'yı user verisi değil, trusted kod/config say.
enum: action
decoder schema'ya uyar; data-plane savunması bunu görmez
Asıl saldırı yüzeyi: downstream parser
JSON'u tüketen taraf gerçek saldırı yüzeyidir. Ajv'nin güvenlik notları bunu net koyar: JSON Schema bazı sanitization'ın yerini alabilir ama diğer API güvenlik önlemlerinin yerini almaz. Üstelik untrusted schema'lar uygulama kodu kadar tehlikelidir: güvenilmeyen ya da untrusted veriden üretilen schema stack overflow, yavaş derleme ve yavaş validation'a yol açabilir.
Güvenilir schema'larda bile DoS tuzakları var: regex ağırlıklı pattern/format ReDoS doğurabilir, allErrors: true hostile input'ta ilk hatadan sonra durmadığı için production'da önerilmez, tarayıcıda precompile edilmemiş validator'lar unsafe-eval gerektirip CSP/XSS dengesini bozabilir. Yani validator'ın yapılandırması ve schema'nın provenance'ı güvenlik modelinin parçasıdır.
Aşağıda her downstream sink kendi savunmasını gösteriyor: HTML için encoding, SQL için parameterization, dosya yolu için canonicalization, tool için policy + human approval. Tek bir genel filtre değil, sink'e özgü kontrol. structured output buraya gelene kadar untrusted kalmalı.
structured output şekil hatalarını büyük ölçüde çözer; ama geçerli bir kabuk, geçersiz bir niyeti taşıyabilir.
Bu yüzden "schema geçti" demeden önce sor: bu değer hangi sink'e gidiyor, kimin otoritesiyle, hangi deterministik kontrol onu durduracak? Tipi doğrula, değere asla güvenme.
Kaynaklar
- S1OpenAI, Structured model outputs (developer guide)
- S2OWASP Top 10 for LLM Applications 2025
- S3NCSC, Prompt injection is not SQL injection (it may be worse), 2025
- S4Greshake et al., Not what you've signed up for: Indirect Prompt Injection, Black Hat USA 2023 (arXiv:2302.12173)
- S5Zhang et al., When Grammar Guides the Attack: Control-Plane Vulnerabilities with Structured Output, 2026 (arXiv:2503.24191)
- S6Shi et al., Prompt Injection Attack to Tool Selection in LLM Agents, NDSS 2026
- S7Ajv, Security considerations (JSON Schema validator)
