GitHub च्या CodeQL 2.26.0 मध्ये AI prompt-injection पॅटर्न शोधण्यासाठी एक इन-बिल्ट क्वेरी (built-in query) जोडली आहे, आणि या बदलामुळे CI पाईपलाईन्समध्ये नवीन धोके सूचित (flag) होऊ लागले आहेत. केवळ अपग्रेड करणे पुरेसे नाही—कोड विकसित होत असताना हा नियम प्रभावी राहील याची खात्री करण्यासाठी टीम्सना रिग्रेशन टेस्ट सूटची (regression test suite) आवश्यकता आहे.

रिग्रेशन फिक्स्चर (regression fixture) का महत्त्वाचे आहे

प्रॉम्प्ट इंजेक्शनमुळे (Prompt injection) अटॅकर लँग्वेज मॉडेलला नंतर पालन करतील असे घातक निर्देश प्रॉम्प्टमध्ये मिसळू शकतो. नवीन क्वेरीसह, स्टॅटिक अनालिसिस अविश्वसनीय स्रोत (untrusted source) पासून मॉडेल-कॉलिंग सिंक (model-calling sink) पर्यंतचा डेटा ट्रॅस करू शकते. जर हा नियम फक्त चालू करून कधीही पडताळला नाही, तर नंतरच्या रिफॅक्टरिंगमुळे (refactor) डेटा-फ्लो पाथ तुटू शकतो आणि अलर्ट शांतपणे गायब होऊ शकतो. रिग्रेशन फिक्स्चर नेमके ते मार्ग कॅप्चर करते जे नियमाला ट्रिगर केले पाहिजेत (किंवा केले नकोत), ज्यामुळे स्टॅटिक-अनालिसिस रिझल्टला एका कराराचे (contract) स्वरूप प्राप्त होते जो बिल्डद्वारे लागू केला जातो.

विश्वसनीय फिक्स्चरचे तीन घटक

  1. Untrusted source (अविश्वसनीय स्रोत) – कोणताही असा फंक्शन जो विश्वसनीय कोड बेसच्या बाहेरून डेटा आणतो (उदा. GitHub issue body, webhook payload).
  2. Prompt construction (प्रॉम्प्ट कन्स्ट्रक्शन) – मॉडेल रिक्वेस्ट तयार करणारा कोड, जो सहसा क्लायंट SDK कॉल असतो.
  3. Model sink (मॉडेल सिंक) – मॉडेलला प्रॉम्प्ट पाठवणारी SDK मेथड. CodeQL च्या डेटा-फ्लो इंजिनला सिंक ओळखण्यासाठी तुमच्या प्रोडक्शन स्टॅक मधून प्रत्यक्ष कॉल पाहणे आवश्यक आहे.

जेव्हा हे तिन्ही घटक उपस्थित असतात, तेव्हाच क्वेरी फायर होते.

टेस्ट फाइल्सचे आयोजन

एक पारंपारिक लेआउट टेस्ट सूट ऑडिट करणे सोपे ठेवतो:

security-fixtures/prompt-injection/
├─ positive/
│  ├─ direct-flow.ts
│  └─ helper-flow.ts
├─ negative/
│  └─ trusted-instruction.ts
└─ expected-alerts.json

Positive फाइल्समध्ये असा कोड असतो ज्याला फ्लॅग (flag) केले पाहिजे; negative फाइल्समध्ये सुरक्षित पॅटर्न असतात ज्यांनी शांत (silent) राहिले पाहिजे.

पॉझिटिव्ह केसेस (Positive cases) लिहिणे

सर्वात सोपे उदाहरण अविश्वसनीय व्हॅल्यूपासून मॉडेल कॉलपर्यंतचा थेट प्रवाह दर्शवते:

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,
  });
}

येथे loadIssueBody हा अविश्वसनीय स्रोत आहे, model.generate हा सिंक आहे, आणि डेटा कोणत्याही सॅनिटायझेशन स्टेपशिवाय (sanitisation step) पास होतो—ज्यासाठी ही क्वेरी डिझाइन केलेली आहे.

दुसरी पॉझिटिव्ह केस डेटाला हेल्पर फंक्शनद्वारे रूट करणे आवश्यक आहे, ज्यामुळे विश्लेषण अप्रत्यक्ष मार्गांचा (indirect paths) पाठलाग करते हे सिद्ध होईल:

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));
}

दोन्ही फाइल्स positive/ अंतर्गत येतात.

निगेटिव्ह केस (Negative case) लिहिणे

निगेटिव्ह फिक्स्चरने हे सिद्ध केले पाहिजे की युजर इनपुट मॉडेलचे निर्देश बदलू शकत नाही. sanitize() नावाचे फंक्शन सुरक्षिततेची खात्री देते असा गृहित धरणे ही एक सामान्य चूक आहे. स्टॅटिक अनालायझर नावाचा वापर पुरावा म्हणून करत नाही, त्यामुळे टेस्टमध्ये कोणत्याही दिशाभूल करणाऱ्या सॅनिटायझेशन स्टबचा (sanitisation stub) वापर टाळला पाहिजे:

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",
  });
}

कारण अविश्वसनीय डेटा कधीही system फील्डपर्यंत पोहोचत नाही, त्यामुळे नियम शांत राहायला हवा.

JSON मध्ये अपेक्षा घोषित करणे

सूटचा कॉन्ट्रॅक्ट expected-alerts.json मध्ये असतो. तो आवश्यक अलर्ट्स आणि स्पष्टपणे प्रतिबंधित मार्ग (forbidden paths) सूचीबद्ध करतो:

{
  "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 च्या जागी CodeQL डॉक्युमेंटेशन किंवा SARIF आउटपुटमध्ये दाखवलेला आयडेंटिफायर (identifier) वापरा. आयडीचा अंदाज लावू नका; CI चेकसाठी अचूक स्ट्रिंग महत्त्वाची असते.

फिक्स्चरला CI मध्ये जोडणे

  1. पाईपलाईनमध्ये वापरल्या जाणाऱ्या CodeQL CLI व्हर्जनला 2.26.0 (किंवा त्यापेक्षा नवीन) वर पिन करा.
  2. फिक्स्चर चालवण्यापूर्वी सध्याच्या चेकआउटमधून एक डिस्पोजेबल डेटाबेस तयार करा.
  3. क्वेरी चालवा, अलर्ट्स कॅप्चर करा आणि त्यांची expected-alerts.json सोबत तुलना करा.
  4. जर कोणताही आवश्यक अलर्ट गायब झाला किंवा एखादा प्रतिबंधित मार्ग अलर्ट देऊ लागला, तर बिल्ड फेल करा.

रिपॉझिटरीमधील एकूण अलर्ट काउंटवर अ‍ॅसर्ट (assert) करू नका—असंबंधित बदलांमुळे संख्या वाढू शकते आणि चुकीचे फेल्युअर (false failures) होऊ शकतात.

अपग्रेडनंतर काय पाहावे

जेव्हा तुम्ही CodeQL नवीन व्हर्जनवर अपडेट करता:

  • आवश्यक अलर्ट अजूनही दिसत आहे – सामान्य रिव्ह्यूसह पुढे जा.
  • आवश्यक अलर्ट गायब झाला आहे – बिल्ड ब्लॉक करा; नवीन व्हर्जनने क्वेरी लॉजिक बदलले आहे की कोडमधील बदलामुळे डेटा फ्लो तुटला आहे याची तपासणी करा.
  • नवीन पॉझिटिव्ह लोकेशन दिसत आहे – ते खरोखरच इंजेक्शन पाथ आहे याची खात्री केल्यावर required लिस्टमध्ये जोडा.
  • निगेटिव्ह कंट्रोल अलर्ट देऊ लागला आहे – मिटिगेशन स्ट्रॅटेजीवर (mitigation strategy) पुन्हा विचार करा; नियम अधिक कडक झाला असावा.

स्टॅटिक अनालिसिस मॉडेल रनटाइमला कसे प्रतिक्रिया देईल हे सिद्ध करू शकत नाही. रिग्रेशन सूटला ॲडव्हर्सरिअल टेस्ट्सनी (adversarial tests) पूरक करा, ज्या प्रत्यक्षात मॉडेलला तयार केलेले प्रॉम्प्ट्स पाठवतात आणि प्रतिसादाची पडताळणी करतात.

निष्कर्ष

CodeQL 2.26.0 तुम्हाला प्रॉम्प्ट-इंजेक्शन बग्स शिप होण्यापूर्वी पकडण्याची क्षमता देते, परंतु फक्त तुम्ही त्या क्षमतेला एका केंद्रित रिग्रेशन फिक्स्चरने लॉक केले तरच. अविश्वसनीय स्रोत, रिअल SDK सिंक्स आणि JSON कॉन्ट्रॅक्टमध्ये स्पष्ट अपेक्षा परिभाषित करून, तुम्ही स्टॅटिक-अनालिसिस नियमाला रिग्रेशन्स थांबवणारे आणि वेगाने विकसित होणाऱ्या अटॅक सरफेसवर सतत लक्ष केंद्रित करणारे गेट (gate) बनवू शकता.