GitHub యొక్క CodeQL 2.26.0 AI prompt-injection నమూనాలను గుర్తించే ఒక built-in queryని జోడించింది, మరియు ఈ మార్పు ఇప్పటికే CI పైప్‌లైన్‌లలో కొత్త రిస్క్‌లను ఫ్లాగ్ చేయడం ప్రారంభించింది. కేవలం అప్‌గ్రేడ్ చేయడం మాత్రమే సరిపోదు—కోడ్ పరిణామం చెందుతున్న కొద్దీ ఆ రూల్ ప్రభావవంతంగా ఉండేలా చూసే రిగ్రెషన్ టెస్ట్ సూట్ (regression test suite) టీమ్‌లకు అవసరం.

రిగ్రెషన్ ఫిక్చర్ (regression fixture) ఎందుకు ముఖ్యం

Prompt injection ద్వారా ఒక అటాకర్ మాలీషియస్ ఇన్‌స్ట్రక్షన్స్‌ను ప్రాంప్ట్‌లో చేర్చవచ్చు, దానిని లాంగ్వేజ్ మోడల్ తర్వాత అనుసరిస్తుంది. కొత్త క్వరీతో, స్టాటిక్ అనాలిసిస్ (static analysis) ఒక untrusted source నుండి మోడల్-కాలింగ్ sink వరకు డేటాను ట్రాస్ చేయగలదు. ఒకవేళ ఈ రూల్‌ను కేవలం ఆన్ చేసి, ఎప్పుడూ వెరిఫై చేయకపోతే, తర్వాత చేసే ఏదైనా రిఫ్యాక్టర్ (refactor) డేటా-ఫ్లో పాత్‌ను దెబ్బతీసి, అలర్ట్ నిశ్శబ్దంగా మాయమైపోవచ్చు. ఒక రిగ్రెషన్ ఫిక్చర్, రూల్‌ను ట్రిగ్గర్ చేయాల్సిన (లేదా చేయకూడని) ఖచ్చితమైన పాత్‌లను క్యాప్చర్ చేస్తుంది, తద్వారా స్టాటిక్-అనాలిసిస్ ఫలితాన్ని బిల్డ్ అమలు చేసే ఒక కాంట్రాక్ట్‌గా మారుస్తుంది.

నమ్మదగిన ఫిక్చర్‌కు కావాల్సిన మూడు అంశాలు

  1. Untrusted source – నమ్మదగిన కోడ్ బేస్ వెలుపల నుండి డేటాను తీసుకువచ్చే ఏదైనా ఫంక్షన్ (ఉదాహరణకు, ఒక GitHub issue body, webhook payload).
  2. Prompt construction – మోడల్ రిక్వెస్ట్‌ను అసెంబుల్ చేసే కోడ్, సాధారణంగా ఇది ఒక client SDK కాల్.
  3. Model sink – ప్రాంప్ట్‌ను మోడల్‌కు పంపే SDK మెథడ్. CodeQL యొక్క data-flow engine, sinkని గుర్తించడానికి మీ production stack నుండి నిజమైన కాల్‌ను చూడాలి.

ఈ మూడింటి presence ఉన్నప్పుడు మాత్రమే క్వరీ ఫైర్ అవుతుంది.

టెస్ట్ ఫైళ్లను నిర్వహించడం

సాంప్రదాయ లేఅవుట్ ఈ సూట్‌ను ఆడిట్ చేయడం సులభతరం చేస్తుంది:

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

Positive ఫైళ్లు ఫ్లాగ్ చేయబడాల్సిన కోడ్‌ను కలిగి ఉంటాయి; negative ఫైళ్లు సైలెంట్‌గా ఉండాల్సిన సురక్షితమైన నమూనాలను కలిగి ఉంటాయి.

Positive cases రాయడం

అత్యంత సరళమైన ఉదాహరణ, ఒక untrusted value నుండి మోడల్ కాల్ వరకు నేరుగా ఉండే ఫ్లోను చూపుతుంది:

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 అనేది untrusted source, model.generate అనేది sink, మరియు డేటా ఎటువంటి sanitisation స్టెప్ లేకుండా పాస్ అవుతుంది—ఖచ్చితంగా క్వరీ దేనిని పట్టుకోవడానికి రూపొందించబడిందో ఇది అదే చేస్తుంది.

రెండవ positive case, డేటాను ఒక హెల్పర్ ఫంక్షన్ ద్వారా పంపాలి, తద్వారా అనాలిసిస్ పరోక్ష పాత్‌లను (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",
  });
}

Untrusted డేటా system ఫీల్డ్‌కు చేరుకోదు కాబట్టి, రూల్ సైలెంట్‌గా ఉండాలి.

JSONలో ఎక్స్‌పెక్టేషన్స్‌ను ప్రకటించడం

ఈ సూట్ యొక్క కాంట్రాక్ట్ expected-alerts.jsonలో ఉంటుంది. ఇది అవసరమైన అలర్ట్‌లను మరియు స్పష్టంగా నిషేధించబడిన పాత్‌లను జాబితా చేస్తుంది:

{
  "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 అవుట్‌పుట్‌లో చూపబడిన ఐడెంటిఫైయర్‌ను ఉంచండి. ఐడిలను ఊహించవద్దు; CI చెక్ కోసం ఖచ్చితమైన స్ట్రింగ్ ముఖ్యం.

ఫిక్చర్‌ను CIకి అనుసంధానించడం (Hooking)

  1. పైప్‌లైన్‌లో ఉపయోగించే CodeQL CLI వెర్షన్‌ను 2.26.0 (లేదా అంతకంటే ఎక్కువ) కి పిన్ చేయండి.
  2. ఫిక్చర్‌ను రన్ చేయడానికి ముందు, ప్రస్తుత checkout నుండి ఒక disposable databaseని బిల్డ్ చేయండి.
  3. క్వరీని రన్ చేయండి, అలర్ట్‌లను క్యాప్చర్ చేయండి మరియు వాటిని expected-alerts.jsonతో పోల్చండి.
  4. ఏదైనా అవసరమైన అలర్ట్ కనిపించకపోయినా లేదా నిషేధించబడిన పాత్ అలర్ట్ ఇస్తున్నా బిల్డ్‌ను ఫెయిల్ చేయండి.

రిపోజిటరీ అంతటా మొత్తం అలర్ట్ కౌంట్‌ను అసర్ట్ (assert) చేయవద్దు—సంబంధం లేని మార్పులు ఆ సంఖ్యను పెంచి, తప్పుడు ఫెయిల్యూర్స్‌కు (false failures) దారితీయవచ్చు.

అప్‌గ్రేడ్ తర్వాత గమనించవలసినవి

మీరు CodeQLని కొత్త వెర్షన్‌కు అప్‌గ్రేడ్ చేసినప్పుడు:

  • Required alert ఇంకా కనిపిస్తుంటే – సాధారణ రివ్యూతో ముందుకు వెళ్లండి.
  • Required alert మాయమైతే – బిల్డ్‌ను బ్లాక్ చేయండి; కొత్త వెర్షన్ క్వరీ లాజిక్‌ను మార్చిందా లేదా కోడ్ మార్పు డేటా ఫ్లోను దెబ్బతీసిందా అనేది పరిశోధించండి.
  • కొత్త positive location కనిపిస్తే – అది నిజమైన ఇంజెక్షన్ పాత్ అని నిర్ధారించుకున్న తర్వాత దానిని required జాబితాలో చేర్చండి.
  • Negative control అలర్ట్ ఇస్తుంటే – మిటిగేషన్ స్ట్రాటజీని (mitigation strategy) మళ్ళీ పరిశీలించండి; రూల్ మరింత కఠినంగా మారినట్లు ఉండవచ్చు.

స్టాటిక్ అనాలిసిస్, రన్‌టైమ్‌లో మోడల్ ఎలా స్పందిస్తుందో నిరూషించలేదు. రిగ్రెషన్ సూట్‌కు తోడుగా, మోడల్‌కు నిజంగా క్రాఫ్టెడ్ ప్రాంప్ట్‌లను పంపి మరియు ప్రతిస్పందనను ధృవీకరించే అడ్వర్సేరియల్ టెస్ట్‌లను (adversarial tests) కూడా నిర్వహించండి.

ముగింపు (Takeaway)

CodeQL 2.26.0, ప్రాంప్ట్-ఇంజెక్షన్ బగ్‌లను అవి షిప్ అవ్వకముందే పట్టుకునే సామర్థ్యాన్ని మీకు ఇస్తుంది, కానీ మీరు ఆ సామర్థ్యాన్ని ఒక ఫోకస్డ్ రిగ్రెషన్ ఫిక్చర్‌తో లాక్ చేసినప్పుడు మాత్రమే ఇది సాధ్యమవుతుంది. Untrusted sources, నిజమైన SDK sinks మరియు JSON కాంట్రాక్ట్‌లో స్పష్టమైన ఎక్స్‌పెక్టేషన్స్‌ను నిర్వచించడం ద్వారా, మీరు ఒక స్టాటిక్-అనాలిసిస్ రూల్‌ను రిగ్రెషన్స్‌ను అడ్డుకునే మరియు వేగంగా మారుతున్న అటాక్ సర్ఫేస్‌పై నిరంతర దృష్టిని సారించే ఒక గేట్‌గా మార్చగలరు.