Skip to content

Commit 3f2f400

Browse files
committed
Improve PromptInjectionMedium.ql & update change-notes
1 parent 9092d86 commit 3f2f400

4 files changed

Lines changed: 46 additions & 8 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: feature
3+
---
4+
* Added `PromptInjectionQuery.qll` library and `prompt_injection_sinks.model.yml` models-as-data file for detecting prompt injection (CWE-1427) in GitHub Actions AI inference workflows. Added `prompt-injection` to control check categories in `ControlChecks.qll`.

actions/ql/lib/codeql/actions/security/PromptInjectionQuery.qll

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,21 +78,30 @@ predicate criticalSeverityPromptInjection(
7878
}
7979

8080
/**
81-
* Gets the relevant event for a sink in any externally triggerable context,
82-
* excluding sinks protected by control checks for the prompt-injection category.
83-
* This is broader than `getRelevantEventForSink` — it includes non-privileged
84-
* events like `pull_request` where an attacker can still control event properties
85-
* (PR title, body, branch name) that flow into AI prompts.
81+
* Gets the relevant event for a sink on any externally triggerable event
82+
* that is NOT already covered by the critical-severity predicate.
83+
* This captures flows on non-privileged events (e.g. `pull_request`),
84+
* read-only privileged events (e.g. `pull_request_target` with read permissions),
85+
* and any other externally triggerable context that Critical excludes.
86+
*
87+
* Only actor/association control checks suppress Medium findings because
88+
* repository checks do not prevent prompt injection — any user who can
89+
* open an issue/PR on the target repo can inject into the prompt content.
8690
*/
8791
Event getRelevantEventForMediumSeverity(DataFlow::Node sink) {
8892
exists(LocalJob job |
8993
job = sink.asExpr().getEnclosingJob() and
9094
job.getATriggerEvent() = result and
9195
result.isExternallyTriggerable() and
92-
not inPrivilegedContext(sink.asExpr(), result) and
9396
not result.getName() = "repository_dispatch" and
94-
not exists(ControlCheck check | check.protects(sink.asExpr(), result, "prompt-injection"))
95-
)
97+
// Only actor/association checks suppress medium findings
98+
not exists(ControlCheck check |
99+
check.protects(sink.asExpr(), result, "prompt-injection") and
100+
(check instanceof ActorCheck or check instanceof AssociationCheck)
101+
)
102+
) and
103+
// Exclude events already reported at critical severity
104+
not result = getRelevantEventForPromptInjection(sink)
96105
}
97106

98107
/**
@@ -123,6 +132,8 @@ private module PromptInjectionConfig implements DataFlow::ConfigSig {
123132
result = sink.getLocation()
124133
or
125134
result = getRelevantEventForPromptInjection(sink).getLocation()
135+
or
136+
result = getRelevantEventForMediumSeverity(sink).getLocation()
126137
}
127138
}
128139

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Added new experimental queries `actions/prompt-injection/critical` and `actions/prompt-injection/medium` to detect prompt injection vulnerabilities (CWE-1427) in GitHub Actions workflows that pass user-controlled data into AI inference action prompts.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: AI PR Template Check on pull_request_target
2+
on:
3+
pull_request_target:
4+
types: [opened]
5+
6+
jobs:
7+
check:
8+
runs-on: ubuntu-latest
9+
permissions:
10+
contents: read
11+
pull-requests: read
12+
steps:
13+
- name: AI template check
14+
uses: warpdotdev/oz-agent-action@v1
15+
with:
16+
prompt: |
17+
Check this PR against the template:
18+
Title: ${{ github.event.pull_request.title }}
19+
Body: ${{ github.event.pull_request.body }}

0 commit comments

Comments
 (0)