GitHub’ın CodeQL 2.26.0 sürümü, yapay zeka istem (prompt) enjeksiyonu modellerini tespit eden yerleşik bir sorgu ekliyor ve bu değişiklik CI süreçlerinin (pipelines) yeni riskleri işaretlemesine şimdiden neden oluyor. Sadece yükseltme yapmak yeterli değildir; ekiplerin, kod geliştikçe kuralın etkili kalmasını garanti altına alacak bir regresyon test paketi (regression test suite) kullanması gerekir.
Bir regresyon düzeneği (fixture) neden önemlidir?
İstem enjeksiyonu (prompt injection), bir saldırganın dil modelinin daha sonra takip edeceği kötü niyetli talimatları bir istemin içine sızdırmasına olanak tanır. Yeni sorgu ile statik analiz, verileri güvenilmeyen bir kaynaktan (untrusted source) model çağıran bir alıcıya (sink) kadar izleyebilir. Eğer kural sadece açılır ve asla doğrulanmazsa, daha sonra yapılacak bir refaktör veri akış yolunu bozabilir ve uyarı sessizce ortadan kalkabilir. Bir regresyon düzeneği, kuralı tetiklemesi (veya tetiklememesi) gereken tam yolları yakalayarak statik analiz sonucunu, derlemenin (build) uyguladığı bir sözleşmeye dönüştürür.
Güvenilir bir düzeneğin üç bileşeni
- Güvenilmeyen kaynak – güvenilir kod tabanının dışından veri getiren herhangi bir fonksiyon (örneğin, bir GitHub issue gövdesi, bir webhook yükü/payload).
- İstem oluşturma – model isteğini bir araya getiren kod, tipik olarak bir istemci SDK'sına yapılan çağrıdır.
- Model alıcısı (sink) – istemi modele gönderen SDK metodu. CodeQL'in veri akışı motorunun (data-flow engine) alıcıyı tanıyabilmesi için üretim (production) yığınınızdan gelen gerçek bir çağrıyı görmesi gerekir.
Sorgu, ancak bu üçü bir araya geldiğinde çalışır.
Test dosyalarını düzenleme
Geleneksel bir düzen, test paketinin denetlenmesini kolaylaştırır:
security-fixtures/prompt-injection/
├─ positive/
│ ├─ direct-flow.ts
│ └─ helper-flow.ts
├─ negative/
│ └─ trusted-instruction.ts
└─ expected-alerts.json
Pozitif dosyalar işaretlenmesi gereken kodları içerir; negatif dosyalar ise sessiz kalması gereken güvenli modelleri barındırır.
Pozitif durumları yazma
En basit örnek, güvenilmeyen bir değerden model çağrısına doğrudan bir akış gösterir:
import { model } from "./supported-client";
declare function loadIssueBody(id: number): Promise<string>;
export async function summarize(id: number) {
const untrusted = await loadIssueBody(id);
return model.generate({
system: "Summarize the issue",
user: untrusted,
});
}
Burada loadIssueBody güvenilmeyen kaynak, model.generate ise alıcıdır (sink) ve veri herhangi bir temizleme (sanitisation) adımı olmadan geçer; bu, sorgunun tam olarak yakalamak üzere tasarlandığı durumdur.
İkinci bir pozitif durum, veriyi bir yardımcı fonksiyon üzerinden yönlendirerek analizin dolaylı yolları takip ettiğini kanıtlamalıdır:
function wrapUserInput(input: string) {
return { system: "Summarize the issue", user: input };
}
export async function summarizeViaHelper(id: number) {
const raw = await loadIssueBody(id);
return model.generate(wrapUserInput(raw));
}
Her iki dosya da positive/ dizini altında yer almalıdır.
Negatif durumu yazma
Negatif düzenek, kullanıcı girişinin modelin talimatını değiştiremeyeceğini kanıtlamalıdır. Yaygın bir hata, sanitize() adlı bir fonksiyonun güvenliği garanti ettiğini varsaymaktır. Statik analiz aracı ismi bir kanıt olarak değerlendirmez, bu nedenle test, yanıltıcı herhangi bir temizleme taslağından (sanitisation stub) kaçınmalıdır:
export async function safeSummarize(id: number) {
const trusted = "Summarize the issue";
const user = await loadIssueBody(id); // not used in the system prompt
return model.generate({
system: trusted,
user: "Static placeholder",
});
}
Güvenilmeyen veri system alanına asla ulaşmadığı için kural sessiz kalmalıdır.
JSON içinde beklentileri tanımlama
Test paketinin sözleşmesi expected-alerts.json dosyasında bulunur. Bu dosya gerekli uyarıları ve açıkça yasaklanmış yolları listeler:
{
"required": [
{
"ruleId": "USE_ACTUAL_RULE_ID",
"pathSuffix": "positive/direct-flow.ts"
},
{
"ruleId": "USE_ACTUAL_RULE_ID",
"pathSuffix": "positive/helper-flow.ts"
}
],
"forbiddenPathSuffixes": [
"negative/trusted-instruction.ts"
]
}
USE_ACTUAL_RULE_ID kısmını CodeQL dokümantasyonunda veya SARIF çıktısında gösterilen tanımlayıcı ile değiştirin. ID'leri tahmin etmeyin; CI kontrolü için tam dize (string) önemlidir.
Düzeneği CI süreçlerine bağlama
- Pipeline'da kullanılan CodeQL CLI sürümünü 2.26.0 (veya daha yeni) sürümüne sabitleyin.
- Düzeneği çalıştırmadan önce mevcut checkout'tan geçici bir veritabanı oluşturun.
- Sorguyu çalıştırın, uyarıları yakalayın ve bunları
expected-alerts.jsonile karşılaştırın. - Gerekli bir uyarı kaybolursa veya yasaklanmış bir yol uyarı vermeye başlarsa derlemeyi (build) başarısız kılın.
Depo genelindeki toplam uyarı sayısını doğrulamayın (assert etmeyin); ilgisiz değişiklikler sayıyı artırabilir ve hatalı başarısızlıklara neden olabilir.
Yükseltme sonrası nelere dikkat edilmeli?
CodeQL sürümünü daha yeni bir sürüme yükselttiğinizde:
- Gerekli uyarı hâlâ görünüyorsa – normal inceleme sürecine devam edin.
- Gerekli uyarı kayboluyorsa – derlemeyi engelleyin; yeni sürümün sorgu mantığını değiştirip değiştirmediğini veya bir kod değişikliğinin veri akışını bozup bozmadığını araştırın.
- Yeni bir pozitif konum ortaya çıkıyorsa – bunun gerçek bir enjeksiyon yolu olduğunu onayladıktan sonra
requiredlistesine ekleyin. - Negatif kontrol uyarı vermeye başlıyorsa – hafifletme (mitigation) stratejisini yeniden gözden geçirin; kural daha katı hale gelmiş olabilir.
Statik analiz, modelin çalışma zamanında (runtime) nasıl tepki vereceğini kanıtlayamaz. Regresyon paketini, modele gerçekten özel olarak hazırlanmış istemler gönderen ve yanıtı doğrulayan saldırgan (adversarial) testlerle tamamlayın.
Özet
CodeQL 2.26.0, istem enjeksiyonu hatalarını henüz yayına alınmadan yakalama yeteneği sunar; ancak bu yeteneği odaklanmış bir regresyon düzeneği ile sabitlemeniz gerekir. Güvenilmeyen kaynakları, gerçek SDK alıcılarını (sinks) ve bir JSON sözleşmesindeki net beklentileri tanımlayarak, statik analiz kuralını regresyonları durduran ve hızla gelişen bir saldırı yüzeyine sürekli dikkat edilmesini sağlayan bir kapıya (gate) dönüştürürsünüz.
