GitHub के CodeQL 2.26.0 में एक इन-बिल्ट क्वेरी जोड़ी गई है जो AI प्रॉम्प्ट-इंजेक्शन (prompt-injection) पैटर्न का पता लगाती है, और इस बदलाव के कारण CI पाइपलाइन्स नए जोखिमों को फ्लैग करना शुरू कर चुकी हैं। केवल अपग्रेड करना ही काफी नहीं है—टीमों को एक रिग्रेशन टेस्ट सूट (regression test suite) की आवश्यकता है जो यह गारंटी दे सके कि कोड विकसित होने के साथ-साथ यह नियम प्रभावी बना रहे।

रिग्रेशन फिक्स्चर (regression fixture) क्यों महत्वपूर्ण है

प्रॉम्प्ट इंजेक्शन एक हमलावर को प्रॉम्प्ट में दुर्भावनापूर्ण निर्देश (malicious instructions) डालने की अनुमति देता है जिसका पालन लैंग्वेज मॉडल बाद में करता है। नई क्वेरी के साथ, स्टैटिक एनालिसिस (static analysis) अनट्रस्टेड सोर्स (untrusted source) से मॉडल-कॉलिंग सिंक (model-calling sink) तक डेटा को ट्रैक कर सकता है। यदि नियम को केवल चालू कर दिया जाए और कभी सत्यापित न किया जाए, तो बाद में किया गया रिफैक्टर (refactor) डेटा-फ्लो पाथ को तोड़ सकता है और अलर्ट चुपचाप गायब हो सकता है। एक रिग्रेशन फिक्स्चर उन सटीक रास्तों को कैप्चर करता है जिन्हें नियम को ट्रिगर (या ट्रिगर नहीं) करना चाहिए, जिससे स्टैटिक-एनालिसिस का परिणाम एक कॉन्ट्रैक्ट बन जाता है जिसे बिल्ड लागू करता है।

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

  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 फाइलों में वह कोड होता है जिसे फ्लैग किया जाना चाहिए; negative फाइलें सुरक्षित पैटर्न रखती हैं जिन्हें शांत (silent) रहना चाहिए।

पॉजिटिव केस लिखना

सबसे सरल उदाहरण एक अनट्रस्टेड वैल्यू से मॉडल कॉल तक सीधा फ्लो दिखाता है:

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) स्टेप के पास हो जाता है—ठीक वैसा ही जिसे पकड़ने के लिए क्वेरी डिज़ाइन की गई है।

दूसरा पॉजिटिव केस डेटा को एक हेल्पर फंक्शन के माध्यम से रूट करना चाहिए, जो यह साबित करता है कि एनालिसिस अप्रत्यक्ष (indirect) रास्तों का अनुसरण करता है:

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/ के अंतर्गत आती हैं।

नेगेटिव केस लिखना

नेगेटिव फिक्स्चर को यह प्रदर्शित करना चाहिए कि यूजर इनपुट मॉडल के निर्देश को नहीं बदल सकता है। एक सामान्य गलती यह मान लेना है कि 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 में अपेक्षाओं (expectations) को घोषित करना

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

{
  "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) से बदलें। IDs का अनुमान न लगाएं; CI चेक के लिए सटीक स्ट्रिंग महत्वपूर्ण है।

फिक्स्चर को CI से जोड़ना

  1. पाइपलाइन में उपयोग किए जाने वाले CodeQL CLI वर्जन को 2.26.0 (या उसके बाद के) पर पिन करें।
  2. फिक्स्चर चलाने से पहले वर्तमान चेकआउट से एक डिस्पोजेबल (disposable) डेटाबेस बनाएं।
  3. क्वेरी चलाएं, अलर्ट कैप्चर करें, और उनकी तुलना expected-alerts.json से करें।
  4. यदि कोई आवश्यक अलर्ट गायब हो जाता है या यदि कोई वर्जित रास्ता अलर्ट देने लगता है, तो बिल्ड को फेल कर दें।

पूरे रिपॉजिटरी में कुल अलर्ट काउंट का दावा (assert) न करें—असंबंधित बदलावों से संख्या बढ़ सकती है और गलत विफलताएं (false failures) हो सकती हैं।

अपग्रेड के बाद किन बातों पर ध्यान दें

जब आप CodeQL को नए वर्जन पर अपडेट करते हैं:

  • आवश्यक अलर्ट अभी भी दिखाई देता है – सामान्य समीक्षा के साथ आगे बढ़ें।
  • आवश्यक अलर्ट गायब हो जाता है – बिल्ड को रोकें; जांचें कि क्या नए वर्जन ने क्वेरी लॉजिक को बदल दिया है या क्या कोड परिवर्तन ने डेटा फ्लो को तोड़ दिया है।
  • नया पॉजिटिव लोकेशन दिखाई देता है – यह पुष्टि करने के बाद कि यह एक वास्तविक इंजेक्शन पाथ है, इसे required सूची में जोड़ें।
  • नेगेटिव कंट्रोल अलर्ट देने लगता है – मिटिगेशन रणनीति (mitigation strategy) पर फिर से विचार करें; नियम अधिक सख्त हो गया हो सकता है।

स्टैटिक एनालिसिस यह साबित नहीं कर सकता कि रनटाइम पर मॉडल कैसे प्रतिक्रिया देगा। रिग्रेशन सूट को एडवर्सरियल टेस्ट (adversarial tests) के साथ पूरक करें जो वास्तव में मॉडल को तैयार किए गए प्रॉम्प्ट भेजते हैं और प्रतिक्रिया को सत्यापित करते हैं।

निष्कर्ष (Takeaway)

CodeQL 2.26.0 आपको प्रॉम्प्ट-इंजेक्शन बग्स को शिप होने से पहले पकड़ने की क्षमता देता है, लेकिन केवल तभी जब आप एक केंद्रित रिग्रेशन फिक्स्चर के साथ उस क्षमता को सुरक्षित कर लेते हैं। अनट्रस्टेड सोर्स, वास्तविक SDK सिंक और एक JSON कॉन्ट्रैक्ट में स्पष्ट अपेक्षाओं को परिभाषित करके, आप एक स्टैटिक-एनालिसिस नियम को एक ऐसे गेट में बदल देते हैं जो रिग्रेशन को रोकता है और तेजी से विकसित होते अटैक सरफेस (attack surface) पर निरंतर ध्यान केंद्रित करने के लिए मजबूर करता है।