Skip to content

Commit 04193f4

Browse files
committed
Une inline expectations
1 parent a9d0a16 commit 04193f4

File tree

6 files changed

+62
-58
lines changed

6 files changed

+62
-58
lines changed

python/ql/lib/semmle/python/security/dataflow/PromptInjectionCustomizations.qll

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,15 @@ module PromptInjection {
4242
* Agent prompt sinks, considered as a flow sink.
4343
*/
4444
class SystemPromptSink extends Sink {
45-
SystemPromptSink() { this = Agent::sink().asSink() or this = OpenAI::sink().asSink() }
45+
SystemPromptSink() { this = [Agent::sink(), OpenAI::sink()].asSink() }
4646
}
4747

4848
private class SinkFromModel extends Sink {
4949
SinkFromModel() { this = ModelOutput::getASinkNode("prompt-injection").asSink() }
5050
}
51+
52+
/**
53+
* A comparison with a constant, considered as a sanitizer-guard.
54+
*/
55+
class ConstCompareAsSanitizerGuard extends Sanitizer, ConstCompareBarrier { }
5156
}

python/ql/lib/semmle/python/security/dataflow/PromptInjectionQuery.qll

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Provides taint-tracking configurations for detecting "prompt injection" vulnerabilities.
2+
* Provides a taint-tracking configuration for detecting "prompt injection" vulnerabilities.
33
*
44
* Note, for performance reasons: only import this file if
55
* `PromptInjection::Configuration` is needed, otherwise
@@ -14,12 +14,9 @@ import PromptInjectionCustomizations::PromptInjection
1414
private module PromptInjectionConfig implements DataFlow::ConfigSig {
1515
predicate isSource(DataFlow::Node node) { node instanceof Source }
1616

17-
predicate isSink(DataFlow::Node node) {
18-
node instanceof Sink
19-
//any()
20-
}
17+
predicate isSink(DataFlow::Node node) { node instanceof Sink }
2118

22-
predicate isBarrierIn(DataFlow::Node node) { node instanceof Sanitizer }
19+
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
2320

2421
predicate observeDiffInformedIncrementalMode() { any() }
2522
}
Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
#select
2+
| agent_instructions.py:9:50:9:89 | ControlFlowNode for BinaryExpr | agent_instructions.py:2:26:2:32 | ControlFlowNode for ImportMember | agent_instructions.py:9:50:9:89 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | agent_instructions.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
3+
| openai_test.py:17:22:17:46 | ControlFlowNode for BinaryExpr | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:17:22:17:46 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
4+
| openai_test.py:18:15:18:19 | ControlFlowNode for query | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:18:15:18:19 | ControlFlowNode for query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
5+
| openai_test.py:22:22:22:46 | ControlFlowNode for BinaryExpr | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:22:22:22:46 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
6+
| openai_test.py:23:15:37:9 | ControlFlowNode for List | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:23:15:37:9 | ControlFlowNode for List | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
7+
| openai_test.py:41:22:41:46 | ControlFlowNode for BinaryExpr | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:41:22:41:46 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
8+
| openai_test.py:42:15:42:19 | ControlFlowNode for query | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:42:15:42:19 | ControlFlowNode for query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
9+
| openai_test.py:47:18:55:13 | ControlFlowNode for Dict | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:47:18:55:13 | ControlFlowNode for Dict | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
10+
| openai_test.py:59:18:70:9 | ControlFlowNode for List | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:59:18:70:9 | ControlFlowNode for List | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
11+
| openai_test.py:74:18:83:9 | ControlFlowNode for List | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:74:18:83:9 | ControlFlowNode for List | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
112
edges
213
| agent_instructions.py:2:26:2:32 | ControlFlowNode for ImportMember | agent_instructions.py:2:26:2:32 | ControlFlowNode for request | provenance | |
314
| agent_instructions.py:2:26:2:32 | ControlFlowNode for request | agent_instructions.py:7:13:7:19 | ControlFlowNode for request | provenance | |
@@ -11,27 +22,27 @@ edges
1122
| openai_test.py:2:26:2:32 | ControlFlowNode for request | openai_test.py:14:12:14:18 | ControlFlowNode for request | provenance | |
1223
| openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:17:22:17:46 | ControlFlowNode for BinaryExpr | provenance | |
1324
| openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:22:22:22:46 | ControlFlowNode for BinaryExpr | provenance | |
14-
| openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:23:15:36:9 | ControlFlowNode for List | provenance | |
15-
| openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:40:22:40:46 | ControlFlowNode for BinaryExpr | provenance | |
16-
| openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:58:18:69:9 | ControlFlowNode for List | provenance | |
17-
| openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:73:18:82:9 | ControlFlowNode for List | provenance | |
25+
| openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:23:15:37:9 | ControlFlowNode for List | provenance | |
26+
| openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:41:22:41:46 | ControlFlowNode for BinaryExpr | provenance | |
27+
| openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:59:18:70:9 | ControlFlowNode for List | provenance | |
28+
| openai_test.py:12:5:12:11 | ControlFlowNode for persona | openai_test.py:74:18:83:9 | ControlFlowNode for List | provenance | |
1829
| openai_test.py:12:15:12:21 | ControlFlowNode for request | openai_test.py:12:15:12:26 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep |
1930
| openai_test.py:12:15:12:21 | ControlFlowNode for request | openai_test.py:13:13:13:24 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep |
2031
| openai_test.py:12:15:12:21 | ControlFlowNode for request | openai_test.py:14:12:14:23 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep |
2132
| openai_test.py:12:15:12:26 | ControlFlowNode for Attribute | openai_test.py:12:15:12:41 | ControlFlowNode for Attribute() | provenance | dict.get |
2233
| openai_test.py:12:15:12:41 | ControlFlowNode for Attribute() | openai_test.py:12:5:12:11 | ControlFlowNode for persona | provenance | |
2334
| openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:18:15:18:19 | ControlFlowNode for query | provenance | |
24-
| openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:23:15:36:9 | ControlFlowNode for List | provenance | |
25-
| openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:41:15:41:19 | ControlFlowNode for query | provenance | |
26-
| openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:46:18:54:13 | ControlFlowNode for Dict | provenance | |
27-
| openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:58:18:69:9 | ControlFlowNode for List | provenance | |
28-
| openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:73:18:82:9 | ControlFlowNode for List | provenance | |
35+
| openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:23:15:37:9 | ControlFlowNode for List | provenance | |
36+
| openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:42:15:42:19 | ControlFlowNode for query | provenance | |
37+
| openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:47:18:55:13 | ControlFlowNode for Dict | provenance | |
38+
| openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:59:18:70:9 | ControlFlowNode for List | provenance | |
39+
| openai_test.py:13:5:13:9 | ControlFlowNode for query | openai_test.py:74:18:83:9 | ControlFlowNode for List | provenance | |
2940
| openai_test.py:13:13:13:19 | ControlFlowNode for request | openai_test.py:13:13:13:24 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep |
3041
| openai_test.py:13:13:13:19 | ControlFlowNode for request | openai_test.py:14:12:14:23 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep |
3142
| openai_test.py:13:13:13:24 | ControlFlowNode for Attribute | openai_test.py:13:13:13:37 | ControlFlowNode for Attribute() | provenance | dict.get |
3243
| openai_test.py:13:13:13:37 | ControlFlowNode for Attribute() | openai_test.py:13:5:13:9 | ControlFlowNode for query | provenance | |
33-
| openai_test.py:14:5:14:8 | ControlFlowNode for role | openai_test.py:46:18:54:13 | ControlFlowNode for Dict | provenance | |
34-
| openai_test.py:14:5:14:8 | ControlFlowNode for role | openai_test.py:58:18:69:9 | ControlFlowNode for List | provenance | |
44+
| openai_test.py:14:5:14:8 | ControlFlowNode for role | openai_test.py:47:18:55:13 | ControlFlowNode for Dict | provenance | |
45+
| openai_test.py:14:5:14:8 | ControlFlowNode for role | openai_test.py:59:18:70:9 | ControlFlowNode for List | provenance | |
3546
| openai_test.py:14:12:14:18 | ControlFlowNode for request | openai_test.py:14:12:14:23 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep |
3647
| openai_test.py:14:12:14:23 | ControlFlowNode for Attribute | openai_test.py:14:12:14:35 | ControlFlowNode for Attribute() | provenance | dict.get |
3748
| openai_test.py:14:12:14:35 | ControlFlowNode for Attribute() | openai_test.py:14:5:14:8 | ControlFlowNode for role | provenance | |
@@ -60,21 +71,10 @@ nodes
6071
| openai_test.py:17:22:17:46 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
6172
| openai_test.py:18:15:18:19 | ControlFlowNode for query | semmle.label | ControlFlowNode for query |
6273
| openai_test.py:22:22:22:46 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
63-
| openai_test.py:23:15:36:9 | ControlFlowNode for List | semmle.label | ControlFlowNode for List |
64-
| openai_test.py:40:22:40:46 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
65-
| openai_test.py:41:15:41:19 | ControlFlowNode for query | semmle.label | ControlFlowNode for query |
66-
| openai_test.py:46:18:54:13 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
67-
| openai_test.py:58:18:69:9 | ControlFlowNode for List | semmle.label | ControlFlowNode for List |
68-
| openai_test.py:73:18:82:9 | ControlFlowNode for List | semmle.label | ControlFlowNode for List |
74+
| openai_test.py:23:15:37:9 | ControlFlowNode for List | semmle.label | ControlFlowNode for List |
75+
| openai_test.py:41:22:41:46 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
76+
| openai_test.py:42:15:42:19 | ControlFlowNode for query | semmle.label | ControlFlowNode for query |
77+
| openai_test.py:47:18:55:13 | ControlFlowNode for Dict | semmle.label | ControlFlowNode for Dict |
78+
| openai_test.py:59:18:70:9 | ControlFlowNode for List | semmle.label | ControlFlowNode for List |
79+
| openai_test.py:74:18:83:9 | ControlFlowNode for List | semmle.label | ControlFlowNode for List |
6980
subpaths
70-
#select
71-
| agent_instructions.py:9:50:9:89 | ControlFlowNode for BinaryExpr | agent_instructions.py:2:26:2:32 | ControlFlowNode for ImportMember | agent_instructions.py:9:50:9:89 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | agent_instructions.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
72-
| openai_test.py:17:22:17:46 | ControlFlowNode for BinaryExpr | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:17:22:17:46 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
73-
| openai_test.py:18:15:18:19 | ControlFlowNode for query | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:18:15:18:19 | ControlFlowNode for query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
74-
| openai_test.py:22:22:22:46 | ControlFlowNode for BinaryExpr | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:22:22:22:46 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
75-
| openai_test.py:23:15:36:9 | ControlFlowNode for List | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:23:15:36:9 | ControlFlowNode for List | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
76-
| openai_test.py:40:22:40:46 | ControlFlowNode for BinaryExpr | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:40:22:40:46 | ControlFlowNode for BinaryExpr | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
77-
| openai_test.py:41:15:41:19 | ControlFlowNode for query | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:41:15:41:19 | ControlFlowNode for query | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
78-
| openai_test.py:46:18:54:13 | ControlFlowNode for Dict | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:46:18:54:13 | ControlFlowNode for Dict | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
79-
| openai_test.py:58:18:69:9 | ControlFlowNode for List | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:58:18:69:9 | ControlFlowNode for List | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
80-
| openai_test.py:73:18:82:9 | ControlFlowNode for List | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | openai_test.py:73:18:82:9 | ControlFlowNode for List | This prompt construction depends on a $@. | openai_test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
query: Security/CWE-1427/PromptInjection.ql
2+
postprocess: utils/test/InlineExpectationsTestQuery.ql

python/ql/test/query-tests/Security/CWE-1427-PromptInjection/agent_instructions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from agents import Agent, Runner
2-
from flask import Flask, request # $ Source=flask
2+
from flask import Flask, request # $ Source
33
app = Flask(__name__)
44

55
@app.route("/parameter-route")
Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from openai import OpenAI, AsyncOpenAI, AzureOpenAI
2-
from flask import Flask, request # $ Source=flask
2+
from flask import Flask, request # $ Source
33
app = Flask(__name__)
44

55
client = OpenAI()
@@ -14,70 +14,71 @@ def get_input_openai():
1414
role = request.args.get("role")
1515

1616
response1 = client.responses.create(
17-
instructions="Talks like a " + persona, # $Alert[py/prompt-injection]
18-
input=query, # $Alert[py/prompt-injection]
17+
instructions="Talks like a " + persona, # $ Alert[py/prompt-injection]
18+
input=query, # $ Alert[py/prompt-injection]
1919
)
2020

2121
response2 = client.responses.create(
22-
instructions="Talks like a " + persona, # $Alert[py/prompt-injection]
22+
instructions="Talks like a " + persona, # $ Alert[py/prompt-injection]
2323
input=[
2424
{
2525
"role": "developer",
26-
"content": "Talk like a " + persona # $Alert[py/prompt-injection]
26+
"content": "Talk like a " + persona
2727
},
2828
{
2929
"role": "user",
3030
"content": [
31-
{"type": "input_text",
32-
"text": query # $Alert[py/prompt-injection]
33-
}
31+
{
32+
"type": "input_text",
33+
"text": query
34+
}
3435
]
3536
}
36-
]
37+
] # $ Alert[py/prompt-injection]
3738
)
3839

3940
response3 = await async_client.responses.create(
40-
instructions="Talks like a " + persona, # $Alert[py/prompt-injection]
41-
input=query, # $Alert[py/prompt-injection]
41+
instructions="Talks like a " + persona, # $ Alert[py/prompt-injection]
42+
input=query, # $ Alert[py/prompt-injection]
4243
)
4344

4445
async with client.realtime.connect(model="gpt-realtime") as connection:
4546
await connection.conversation.item.create(
4647
item={
4748
"type": "message",
48-
"role": role, # $Alert[py/prompt-injection]
49+
"role": role,
4950
"content": [
5051
{"type": "input_text",
51-
"text": query # $Alert[py/prompt-injection]
52+
"text": query
5253
}
5354
],
54-
}
55+
} # $ Alert[py/prompt-injection]
5556
)
5657

5758
completion1 = client.chat.completions.create(
5859
messages=[
5960
{"role": "developer",
60-
"content": "Talk like a " + persona}, # $Alert[py/prompt-injection]
61+
"content": "Talk like a " + persona},
6162
{
6263
"role": "user",
63-
"content": query, # $Alert[py/prompt-injection]
64+
"content": query,
6465
},
6566
{
66-
"role": role, # $Alert[py/prompt-injection]
67-
"content": query, # $Alert[py/prompt-injection]
67+
"role": role,
68+
"content": query,
6869
}
69-
]
70+
] # $ Alert[py/prompt-injection]
7071
)
7172

7273
completion2 = azure_client.chat.completions.create(
7374
messages=[
7475
{
7576
"role": "developer",
76-
"content": "Talk like a " + persona # $Alert[py/prompt-injection]
77+
"content": "Talk like a " + persona
7778
},
7879
{
7980
"role": "user",
80-
"content": query, # $Alert[py/prompt-injection]
81+
"content": query,
8182
}
82-
]
83+
] # $ Alert[py/prompt-injection]
8384
)

0 commit comments

Comments
 (0)