Build a Prompt-Injection Regression Fixture for CodeQL 2.26.0
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. The examples below are implementation templates, not results from a repository I tested.
Model a path, not a phrase
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.
// 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.
Assert SARIF evidence
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.
Treat upgrades as security changes
| 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.
Comments
No comments yet. Start the discussion.