# Build a Prompt-Injection Regression Fixture for CodeQL 2.26.0

> Source: <https://dev.to/jaryn_123/build-a-prompt-injection-regression-fixture-for-codeql-2260-42ap>
> Published: 2026-07-16 04:00:01+00:00

GitHub announced on July 10, 2026 that CodeQL 2.26.0 adds AI prompt-injection detection. Enabling a query is useful; owning a regression test is better.

Primary source: [GitHub Changelog, July 10, 2026](https://github.blog/changelog/2026-07-10-codeql-2-26-0-adds-kotlin-2-4-0-support-and-ai-prompt-injection-detection/).

The examples below are implementation templates, not results from a repository I tested.

A useful fixture contains an untrusted source, prompt construction, and a model sink:

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

Do not test for the literal phrase `ignore previous instructions`

. Static analysis needs a data-flow path. Preserve a supported SDK call from your production stack so CodeQL can recognize the sink.

``` js
// Intentionally vulnerable fixture. Never ship this path.
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,
  });
}
```

Add a second positive case that passes the value through a helper. Then add a negative control where attacker input cannot select or alter the instruction. A function named `sanitize()`

is not evidence of sanitization.

Uploading SARIF alone does not create a regression gate. Commit the expected rule and fixture location:

```
{
  "required": [
    {
      "ruleId": "REPLACE_WITH_DOCUMENTED_RULE_ID",
      "pathSuffix": "positive/direct-flow.ts"
    }
  ],
  "forbiddenPathSuffixes": ["negative/trusted-instruction.ts"]
}
```

Keep the rule ID as a placeholder until it is copied from the CodeQL 2.26.0 documentation or an observed SARIF result. Machine-facing identifiers should never be guessed.

A small assertion can compare `runs[].results[].ruleId`

and each physical location against this file. Fail when a required alert disappears or a negative fixture starts alerting. Do not assert the total number of repository alerts; unrelated code changes make that brittle.

| Result after upgrade | Action |
|---|---|
| Required alert remains | Continue normal review |
| Required alert disappears | Block until query, model, build, or fixture changes are explained |
| New positive location appears | Inspect and deliberately update expectations |
| Negative control alerts | Revisit the mitigation assumption before suppressing |

Pin the CodeQL CLI or action version, record it in CI, and run the fixture on a disposable database. Keep runtime adversarial tests too: static analysis cannot prove how a model will react, and custom wrappers or unsupported SDKs may not be modeled.

The goal is intentionally narrow: make one important untrusted-to-model path an executable repository contract instead of a changelog checkbox.
