From ea87f594808b8be0c2431367404a7327877219db Mon Sep 17 00:00:00 2001 From: Sotiris Dragonas <36576941+BazookaMusic@users.noreply.github.com> Date: Thu, 18 Jun 2026 17:32:10 +0300 Subject: [PATCH] JS: Add and reclassify prompt-injection sinks for AI SDKs Add missing system/user prompt-injection sinks across the OpenAI, Anthropic, and Google GenAI JavaScript models: - OpenAI videos.create/edit/extend/remix prompts (user) - OpenAI beta.realtime.sessions.create instructions (system) - Anthropic legacy completions.create prompt (user) - Google GenAI caches.create config.systemInstruction (system) - Google GenAI caches.create config.contents (user) Also reclassify the OpenAI legacy completions.create prompt from system-prompt-injection to user-prompt-injection: the legacy /v1/completions endpoint takes a single free-form prompt with no role separation, so it is the text-in/text-out equivalent of a user message. Note: videos.remix takes the prompt in Argument[1] (remix(videoID, body)), and Google GenAI caches.create nests both contents and systemInstruction under config, so the model entries differ slightly from a naive mapping. Add corresponding test cases with inline annotations and regenerate the .expected files. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../2026-06-18-prompt-injection-sinks.md | 5 ++ javascript/ql/lib/ext/anthropic.model.yml | 1 + javascript/ql/lib/ext/google-genai.model.yml | 2 + javascript/ql/lib/ext/openai.model.yml | 4 +- .../SystemPromptInjection.expected | 75 ++++++++++--------- .../SystemPromptInjection/gemini_test.js | 11 +++ .../SystemPromptInjection/openai_test.js | 12 ++- .../UserPromptInjection.expected | 74 +++++++++++------- .../anthropic_user_test.js | 8 ++ .../UserPromptInjection/gemini_user_test.js | 9 +++ .../UserPromptInjection/openai_user_test.js | 20 +++++ 11 files changed, 156 insertions(+), 65 deletions(-) create mode 100644 javascript/ql/lib/change-notes/2026-06-18-prompt-injection-sinks.md diff --git a/javascript/ql/lib/change-notes/2026-06-18-prompt-injection-sinks.md b/javascript/ql/lib/change-notes/2026-06-18-prompt-injection-sinks.md new file mode 100644 index 000000000000..3ea46670acd1 --- /dev/null +++ b/javascript/ql/lib/change-notes/2026-06-18-prompt-injection-sinks.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +* Added more prompt-injection sinks for the OpenAI, Anthropic, and Google GenAI SDKs: OpenAI `videos.create`/`edit`/`extend`/`remix` (Sora) prompts and `beta.realtime.sessions.create` instructions, Anthropic legacy `completions.create` prompts, and Google GenAI `caches.create` cached contents and system instructions. +* The OpenAI legacy `completions.create` prompt is now treated as a user-prompt-injection sink instead of a system-prompt-injection sink, since the legacy `/v1/completions` endpoint takes a single free-form prompt with no role separation. diff --git a/javascript/ql/lib/ext/anthropic.model.yml b/javascript/ql/lib/ext/anthropic.model.yml index bf0c953e07f7..80e829256971 100644 --- a/javascript/ql/lib/ext/anthropic.model.yml +++ b/javascript/ql/lib/ext/anthropic.model.yml @@ -10,6 +10,7 @@ extensions: extensible: sinkModel data: - ["anthropic.Client", "Member[messages].Member[create].Argument[0].Member[system]", "system-prompt-injection"] + - ["anthropic.Client", "Member[completions].Member[create].Argument[0].Member[prompt]", "user-prompt-injection"] - ["anthropic.Client", "Member[messages].Member[create].Argument[0].Member[system].ArrayElement.Member[text]", "system-prompt-injection"] - ["anthropic.Client", "Member[beta].Member[messages].Member[create].Argument[0].Member[system]", "system-prompt-injection"] - ["anthropic.Client", "Member[beta].Member[messages].Member[create].Argument[0].Member[system].ArrayElement.Member[text]", "system-prompt-injection"] diff --git a/javascript/ql/lib/ext/google-genai.model.yml b/javascript/ql/lib/ext/google-genai.model.yml index 9ff8fd44e4b9..9b9796d4fa9a 100644 --- a/javascript/ql/lib/ext/google-genai.model.yml +++ b/javascript/ql/lib/ext/google-genai.model.yml @@ -13,6 +13,7 @@ extensions: - ["google-genai.Client", "Member[chats].Member[create].Argument[0].Member[config].Member[systemInstruction]", "system-prompt-injection"] - ["google-genai.Client", "Member[chats].Member[create].ReturnValue.Member[sendMessage].Argument[0].Member[config].Member[systemInstruction]", "system-prompt-injection"] - ["google-genai.Client", "Member[live].Member[connect].Argument[0].Member[config].Member[systemInstruction]", "system-prompt-injection"] + - ["google-genai.Client", "Member[caches].Member[create].Argument[0].Member[config].Member[systemInstruction]", "system-prompt-injection"] - ["google-genai.Client", "Member[models].Member[generateContent,generateContentStream].Argument[0].Member[contents]", "user-prompt-injection"] - ["google-genai.Client", "Member[models].Member[generateImages].Argument[0].Member[prompt]", "user-prompt-injection"] - ["google-genai.Client", "Member[models].Member[editImage].Argument[0].Member[prompt]", "user-prompt-injection"] @@ -20,3 +21,4 @@ extensions: - ["google-genai.Client", "Member[chats].Member[create].ReturnValue.Member[sendMessage,sendMessageStream].Argument[0].Member[message]", "user-prompt-injection"] - ["google-genai.Client", "Member[chats].Member[create].ReturnValue.Member[sendMessage,sendMessageStream].Argument[0].Member[content]", "user-prompt-injection"] - ["google-genai.Client", "Member[interactions].Member[create].Argument[0].Member[input]", "user-prompt-injection"] + - ["google-genai.Client", "Member[caches].Member[create].Argument[0].Member[config].Member[contents]", "user-prompt-injection"] diff --git a/javascript/ql/lib/ext/openai.model.yml b/javascript/ql/lib/ext/openai.model.yml index a979842e926b..bbccbe5a8020 100644 --- a/javascript/ql/lib/ext/openai.model.yml +++ b/javascript/ql/lib/ext/openai.model.yml @@ -12,7 +12,7 @@ extensions: extensible: sinkModel data: - ["openai.Client", "Member[responses].Member[create].Argument[0].Member[instructions]", "system-prompt-injection"] - - ["openai.Client", "Member[completions].Member[create].Argument[0].Member[prompt]", "system-prompt-injection"] + - ["openai.Client", "Member[beta].Member[realtime].Member[sessions].Member[create].Argument[0].Member[instructions]", "system-prompt-injection"] - ["openai.Client", "Member[beta].Member[assistants].Member[create].Argument[0].Member[instructions]", "system-prompt-injection"] - ["openai.Client", "Member[beta].Member[assistants].Member[update].Argument[1].Member[instructions]", "system-prompt-injection"] - ["openai.Client", "Member[beta].Member[threads].Member[runs].Member[create].Argument[1].Member[instructions,additional_instructions]", "system-prompt-injection"] @@ -25,3 +25,5 @@ extensions: - ["@openai/guardrails", "Member[GuardrailAgent].Member[create].Argument[2]", "system-prompt-injection"] - ["@openai/agents", "Member[run].Argument[1]", "user-prompt-injection"] - ["@openai/agents", "Member[Runner].Instance.Member[run].Argument[1]", "user-prompt-injection"] + - ["openai.Client", "Member[videos].Member[create,edit,extend].Argument[0].Member[prompt]", "user-prompt-injection"] + - ["openai.Client", "Member[videos].Member[remix].Argument[1].Member[prompt]", "user-prompt-injection"] diff --git a/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/SystemPromptInjection.expected b/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/SystemPromptInjection.expected index d6594252a7e3..d9b7e43a33a1 100644 --- a/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/SystemPromptInjection.expected +++ b/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/SystemPromptInjection.expected @@ -23,6 +23,7 @@ | gemini_test.js:85:26:85:49 | "Talk l ... persona | gemini_test.js:8:19:8:35 | req.query.persona | gemini_test.js:85:26:85:49 | "Talk l ... persona | This system prompt depends on a $@. | gemini_test.js:8:19:8:35 | req.query.persona | user-provided value | | gemini_test.js:95:26:95:49 | "Talk l ... persona | gemini_test.js:8:19:8:35 | req.query.persona | gemini_test.js:95:26:95:49 | "Talk l ... persona | This system prompt depends on a $@. | gemini_test.js:8:19:8:35 | req.query.persona | user-provided value | | gemini_test.js:105:26:105:49 | "Talk l ... persona | gemini_test.js:8:19:8:35 | req.query.persona | gemini_test.js:105:26:105:49 | "Talk l ... persona | This system prompt depends on a $@. | gemini_test.js:8:19:8:35 | req.query.persona | user-provided value | +| gemini_test.js:119:26:119:49 | "Talk l ... persona | gemini_test.js:8:19:8:35 | req.query.persona | gemini_test.js:119:26:119:49 | "Talk l ... persona | This system prompt depends on a $@. | gemini_test.js:8:19:8:35 | req.query.persona | user-provided value | | langchain_test.js:16:37:16:60 | "Talk l ... persona | langchain_test.js:9:19:9:35 | req.query.persona | langchain_test.js:16:37:16:60 | "Talk l ... persona | This system prompt depends on a $@. | langchain_test.js:9:19:9:35 | req.query.persona | user-provided value | | langchain_test.js:19:14:19:37 | "Talk l ... persona | langchain_test.js:9:19:9:35 | req.query.persona | langchain_test.js:19:14:19:37 | "Talk l ... persona | This system prompt depends on a $@. | langchain_test.js:9:19:9:35 | req.query.persona | user-provided value | | langchain_test.js:25:19:25:42 | "Talk l ... persona | langchain_test.js:9:19:9:35 | req.query.persona | langchain_test.js:25:19:25:42 | "Talk l ... persona | This system prompt depends on a $@. | langchain_test.js:9:19:9:35 | req.query.persona | user-provided value | @@ -33,13 +34,13 @@ | openai_test.js:83:18:83:41 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:83:18:83:41 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | | openai_test.js:97:19:97:42 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:97:19:97:42 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | | openai_test.js:110:18:110:41 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:110:18:110:41 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | -| openai_test.js:120:13:120:36 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:120:13:120:36 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | -| openai_test.js:129:19:129:42 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:129:19:129:42 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | -| openai_test.js:134:19:134:42 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:134:19:134:42 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | -| openai_test.js:140:19:140:42 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:140:19:140:42 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | -| openai_test.js:146:30:146:58 | "Also t ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:146:30:146:58 | "Also t ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | -| openai_test.js:152:14:152:37 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:152:14:152:37 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | -| openai_test.js:164:32:164:55 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:164:32:164:55 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | +| openai_test.js:128:19:128:42 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:128:19:128:42 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | +| openai_test.js:137:19:137:42 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:137:19:137:42 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | +| openai_test.js:142:19:142:42 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:142:19:142:42 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | +| openai_test.js:148:19:148:42 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:148:19:148:42 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | +| openai_test.js:154:30:154:58 | "Also t ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:154:30:154:58 | "Also t ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | +| openai_test.js:160:14:160:37 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:160:14:160:37 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | +| openai_test.js:172:32:172:55 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:172:32:172:55 | "Talk l ... persona | This system prompt depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | | openrouter_test.js:23:18:23:41 | "Talk l ... persona | openrouter_test.js:12:19:12:35 | req.query.persona | openrouter_test.js:23:18:23:41 | "Talk l ... persona | This system prompt depends on a $@. | openrouter_test.js:12:19:12:35 | req.query.persona | user-provided value | | openrouter_test.js:38:18:38:41 | "Talk l ... persona | openrouter_test.js:12:19:12:35 | req.query.persona | openrouter_test.js:38:18:38:41 | "Talk l ... persona | This system prompt depends on a $@. | openrouter_test.js:12:19:12:35 | req.query.persona | user-provided value | | openrouter_test.js:52:19:52:42 | "Talk l ... persona | openrouter_test.js:12:19:12:35 | req.query.persona | openrouter_test.js:52:19:52:42 | "Talk l ... persona | This system prompt depends on a $@. | openrouter_test.js:12:19:12:35 | req.query.persona | user-provided value | @@ -109,6 +110,7 @@ edges | gemini_test.js:8:9:8:15 | persona | gemini_test.js:85:43:85:49 | persona | provenance | | | gemini_test.js:8:9:8:15 | persona | gemini_test.js:95:43:95:49 | persona | provenance | | | gemini_test.js:8:9:8:15 | persona | gemini_test.js:105:43:105:49 | persona | provenance | | +| gemini_test.js:8:9:8:15 | persona | gemini_test.js:119:43:119:49 | persona | provenance | | | gemini_test.js:8:19:8:35 | req.query.persona | gemini_test.js:8:9:8:15 | persona | provenance | | | gemini_test.js:18:43:18:49 | persona | gemini_test.js:18:26:18:49 | "Talk l ... persona | provenance | | | gemini_test.js:30:42:30:48 | persona | gemini_test.js:30:25:30:48 | "Talk l ... persona | provenance | | @@ -116,6 +118,7 @@ edges | gemini_test.js:85:43:85:49 | persona | gemini_test.js:85:26:85:49 | "Talk l ... persona | provenance | | | gemini_test.js:95:43:95:49 | persona | gemini_test.js:95:26:95:49 | "Talk l ... persona | provenance | | | gemini_test.js:105:43:105:49 | persona | gemini_test.js:105:26:105:49 | "Talk l ... persona | provenance | | +| gemini_test.js:119:43:119:49 | persona | gemini_test.js:119:26:119:49 | "Talk l ... persona | provenance | | | langchain_test.js:9:9:9:15 | persona | langchain_test.js:16:54:16:60 | persona | provenance | | | langchain_test.js:9:9:9:15 | persona | langchain_test.js:19:31:19:37 | persona | provenance | | | langchain_test.js:9:9:9:15 | persona | langchain_test.js:25:36:25:42 | persona | provenance | | @@ -130,13 +133,13 @@ edges | openai_test.js:11:9:11:15 | persona | openai_test.js:83:35:83:41 | persona | provenance | | | openai_test.js:11:9:11:15 | persona | openai_test.js:97:36:97:42 | persona | provenance | | | openai_test.js:11:9:11:15 | persona | openai_test.js:110:35:110:41 | persona | provenance | | -| openai_test.js:11:9:11:15 | persona | openai_test.js:120:30:120:36 | persona | provenance | | -| openai_test.js:11:9:11:15 | persona | openai_test.js:129:36:129:42 | persona | provenance | | -| openai_test.js:11:9:11:15 | persona | openai_test.js:134:36:134:42 | persona | provenance | | -| openai_test.js:11:9:11:15 | persona | openai_test.js:140:36:140:42 | persona | provenance | | -| openai_test.js:11:9:11:15 | persona | openai_test.js:146:52:146:58 | persona | provenance | | -| openai_test.js:11:9:11:15 | persona | openai_test.js:152:31:152:37 | persona | provenance | | -| openai_test.js:11:9:11:15 | persona | openai_test.js:164:49:164:55 | persona | provenance | | +| openai_test.js:11:9:11:15 | persona | openai_test.js:128:36:128:42 | persona | provenance | | +| openai_test.js:11:9:11:15 | persona | openai_test.js:137:36:137:42 | persona | provenance | | +| openai_test.js:11:9:11:15 | persona | openai_test.js:142:36:142:42 | persona | provenance | | +| openai_test.js:11:9:11:15 | persona | openai_test.js:148:36:148:42 | persona | provenance | | +| openai_test.js:11:9:11:15 | persona | openai_test.js:154:52:154:58 | persona | provenance | | +| openai_test.js:11:9:11:15 | persona | openai_test.js:160:31:160:37 | persona | provenance | | +| openai_test.js:11:9:11:15 | persona | openai_test.js:172:49:172:55 | persona | provenance | | | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:11:9:11:15 | persona | provenance | | | openai_test.js:19:36:19:42 | persona | openai_test.js:19:19:19:42 | "Talk l ... persona | provenance | | | openai_test.js:29:35:29:41 | persona | openai_test.js:29:18:29:41 | "Talk l ... persona | provenance | | @@ -145,13 +148,13 @@ edges | openai_test.js:83:35:83:41 | persona | openai_test.js:83:18:83:41 | "Talk l ... persona | provenance | | | openai_test.js:97:36:97:42 | persona | openai_test.js:97:19:97:42 | "Talk l ... persona | provenance | | | openai_test.js:110:35:110:41 | persona | openai_test.js:110:18:110:41 | "Talk l ... persona | provenance | | -| openai_test.js:120:30:120:36 | persona | openai_test.js:120:13:120:36 | "Talk l ... persona | provenance | | -| openai_test.js:129:36:129:42 | persona | openai_test.js:129:19:129:42 | "Talk l ... persona | provenance | | -| openai_test.js:134:36:134:42 | persona | openai_test.js:134:19:134:42 | "Talk l ... persona | provenance | | -| openai_test.js:140:36:140:42 | persona | openai_test.js:140:19:140:42 | "Talk l ... persona | provenance | | -| openai_test.js:146:52:146:58 | persona | openai_test.js:146:30:146:58 | "Also t ... persona | provenance | | -| openai_test.js:152:31:152:37 | persona | openai_test.js:152:14:152:37 | "Talk l ... persona | provenance | | -| openai_test.js:164:49:164:55 | persona | openai_test.js:164:32:164:55 | "Talk l ... persona | provenance | | +| openai_test.js:128:36:128:42 | persona | openai_test.js:128:19:128:42 | "Talk l ... persona | provenance | | +| openai_test.js:137:36:137:42 | persona | openai_test.js:137:19:137:42 | "Talk l ... persona | provenance | | +| openai_test.js:142:36:142:42 | persona | openai_test.js:142:19:142:42 | "Talk l ... persona | provenance | | +| openai_test.js:148:36:148:42 | persona | openai_test.js:148:19:148:42 | "Talk l ... persona | provenance | | +| openai_test.js:154:52:154:58 | persona | openai_test.js:154:30:154:58 | "Also t ... persona | provenance | | +| openai_test.js:160:31:160:37 | persona | openai_test.js:160:14:160:37 | "Talk l ... persona | provenance | | +| openai_test.js:172:49:172:55 | persona | openai_test.js:172:32:172:55 | "Talk l ... persona | provenance | | | openrouter_test.js:12:9:12:15 | persona | openrouter_test.js:23:35:23:41 | persona | provenance | | | openrouter_test.js:12:9:12:15 | persona | openrouter_test.js:38:35:38:41 | persona | provenance | | | openrouter_test.js:12:9:12:15 | persona | openrouter_test.js:52:36:52:42 | persona | provenance | | @@ -235,6 +238,8 @@ nodes | gemini_test.js:95:43:95:49 | persona | semmle.label | persona | | gemini_test.js:105:26:105:49 | "Talk l ... persona | semmle.label | "Talk l ... persona | | gemini_test.js:105:43:105:49 | persona | semmle.label | persona | +| gemini_test.js:119:26:119:49 | "Talk l ... persona | semmle.label | "Talk l ... persona | +| gemini_test.js:119:43:119:49 | persona | semmle.label | persona | | langchain_test.js:9:9:9:15 | persona | semmle.label | persona | | langchain_test.js:9:19:9:35 | req.query.persona | semmle.label | req.query.persona | | langchain_test.js:16:37:16:60 | "Talk l ... persona | semmle.label | "Talk l ... persona | @@ -259,20 +264,20 @@ nodes | openai_test.js:97:36:97:42 | persona | semmle.label | persona | | openai_test.js:110:18:110:41 | "Talk l ... persona | semmle.label | "Talk l ... persona | | openai_test.js:110:35:110:41 | persona | semmle.label | persona | -| openai_test.js:120:13:120:36 | "Talk l ... persona | semmle.label | "Talk l ... persona | -| openai_test.js:120:30:120:36 | persona | semmle.label | persona | -| openai_test.js:129:19:129:42 | "Talk l ... persona | semmle.label | "Talk l ... persona | -| openai_test.js:129:36:129:42 | persona | semmle.label | persona | -| openai_test.js:134:19:134:42 | "Talk l ... persona | semmle.label | "Talk l ... persona | -| openai_test.js:134:36:134:42 | persona | semmle.label | persona | -| openai_test.js:140:19:140:42 | "Talk l ... persona | semmle.label | "Talk l ... persona | -| openai_test.js:140:36:140:42 | persona | semmle.label | persona | -| openai_test.js:146:30:146:58 | "Also t ... persona | semmle.label | "Also t ... persona | -| openai_test.js:146:52:146:58 | persona | semmle.label | persona | -| openai_test.js:152:14:152:37 | "Talk l ... persona | semmle.label | "Talk l ... persona | -| openai_test.js:152:31:152:37 | persona | semmle.label | persona | -| openai_test.js:164:32:164:55 | "Talk l ... persona | semmle.label | "Talk l ... persona | -| openai_test.js:164:49:164:55 | persona | semmle.label | persona | +| openai_test.js:128:19:128:42 | "Talk l ... persona | semmle.label | "Talk l ... persona | +| openai_test.js:128:36:128:42 | persona | semmle.label | persona | +| openai_test.js:137:19:137:42 | "Talk l ... persona | semmle.label | "Talk l ... persona | +| openai_test.js:137:36:137:42 | persona | semmle.label | persona | +| openai_test.js:142:19:142:42 | "Talk l ... persona | semmle.label | "Talk l ... persona | +| openai_test.js:142:36:142:42 | persona | semmle.label | persona | +| openai_test.js:148:19:148:42 | "Talk l ... persona | semmle.label | "Talk l ... persona | +| openai_test.js:148:36:148:42 | persona | semmle.label | persona | +| openai_test.js:154:30:154:58 | "Also t ... persona | semmle.label | "Also t ... persona | +| openai_test.js:154:52:154:58 | persona | semmle.label | persona | +| openai_test.js:160:14:160:37 | "Talk l ... persona | semmle.label | "Talk l ... persona | +| openai_test.js:160:31:160:37 | persona | semmle.label | persona | +| openai_test.js:172:32:172:55 | "Talk l ... persona | semmle.label | "Talk l ... persona | +| openai_test.js:172:49:172:55 | persona | semmle.label | persona | | openrouter_test.js:12:9:12:15 | persona | semmle.label | persona | | openrouter_test.js:12:19:12:35 | req.query.persona | semmle.label | req.query.persona | | openrouter_test.js:23:18:23:41 | "Talk l ... persona | semmle.label | "Talk l ... persona | diff --git a/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/gemini_test.js b/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/gemini_test.js index f4b0a69820b8..ce046d29ac67 100644 --- a/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/gemini_test.js +++ b/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/gemini_test.js @@ -109,6 +109,17 @@ app.get("/test", async (req, res) => { }, }); + // === caches.create: config.systemInstruction === + + // SHOULD ALERT + const cache = await ai.caches.create({ + model: "gemini-2.0-flash", + config: { + contents: "Some document to cache", + systemInstruction: "Talk like a " + persona, // $ Alert[js/system-prompt-injection] + }, + }); + // === Sanitizer: constant comparison === // SHOULD NOT ALERT diff --git a/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/openai_test.js b/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/openai_test.js index de872e0aa925..d8f524771bc4 100644 --- a/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/openai_test.js +++ b/javascript/ql/test/Security/CWE-1427/SystemPromptInjection/openai_test.js @@ -114,10 +114,18 @@ app.get("/test", async (req, res) => { // === Legacy Completions API === - // prompt (SHOULD ALERT) + // prompt (SHOULD NOT ALERT for system - reclassified as user-prompt-injection) const l1 = await client.completions.create({ model: "gpt-3.5-turbo-instruct", - prompt: "Talk like a " + persona, // $ Alert[js/system-prompt-injection] + prompt: "Talk like a " + persona, // OK - legacy completions prompt is a user-prompt-injection sink + }); + + // === Realtime API (beta) === + + // beta.realtime.sessions.create instructions (SHOULD ALERT) + const rt1 = await client.beta.realtime.sessions.create({ + model: "gpt-4o-realtime-preview", + instructions: "Talk like a " + persona, // $ Alert[js/system-prompt-injection] }); // === Assistants API (beta) === diff --git a/javascript/ql/test/Security/CWE-1427/UserPromptInjection/UserPromptInjection.expected b/javascript/ql/test/Security/CWE-1427/UserPromptInjection/UserPromptInjection.expected index d243ea58d811..e3adc857a8e6 100644 --- a/javascript/ql/test/Security/CWE-1427/UserPromptInjection/UserPromptInjection.expected +++ b/javascript/ql/test/Security/CWE-1427/UserPromptInjection/UserPromptInjection.expected @@ -1,12 +1,14 @@ #select | anthropic_user_test.js:18:18:18:26 | userInput | anthropic_user_test.js:8:21:8:39 | req.query.userInput | anthropic_user_test.js:18:18:18:26 | userInput | This prompt construction depends on a $@. | anthropic_user_test.js:8:21:8:39 | req.query.userInput | user-provided value | | anthropic_user_test.js:31:18:31:26 | userInput | anthropic_user_test.js:8:21:8:39 | req.query.userInput | anthropic_user_test.js:31:18:31:26 | userInput | This prompt construction depends on a $@. | anthropic_user_test.js:8:21:8:39 | req.query.userInput | user-provided value | +| anthropic_user_test.js:41:13:41:51 | `\\n\\nHu ... stant:` | anthropic_user_test.js:8:21:8:39 | req.query.userInput | anthropic_user_test.js:41:13:41:51 | `\\n\\nHu ... stant:` | This prompt construction depends on a $@. | anthropic_user_test.js:8:21:8:39 | req.query.userInput | user-provided value | | gemini_user_test.js:14:15:14:23 | userInput | gemini_user_test.js:8:21:8:39 | req.query.userInput | gemini_user_test.js:14:15:14:23 | userInput | This prompt construction depends on a $@. | gemini_user_test.js:8:21:8:39 | req.query.userInput | user-provided value | | gemini_user_test.js:26:19:26:27 | userInput | gemini_user_test.js:8:21:8:39 | req.query.userInput | gemini_user_test.js:26:19:26:27 | userInput | This prompt construction depends on a $@. | gemini_user_test.js:8:21:8:39 | req.query.userInput | user-provided value | | gemini_user_test.js:37:15:37:23 | userInput | gemini_user_test.js:8:21:8:39 | req.query.userInput | gemini_user_test.js:37:15:37:23 | userInput | This prompt construction depends on a $@. | gemini_user_test.js:8:21:8:39 | req.query.userInput | user-provided value | | gemini_user_test.js:44:13:44:21 | userInput | gemini_user_test.js:8:21:8:39 | req.query.userInput | gemini_user_test.js:44:13:44:21 | userInput | This prompt construction depends on a $@. | gemini_user_test.js:8:21:8:39 | req.query.userInput | user-provided value | | gemini_user_test.js:51:13:51:21 | userInput | gemini_user_test.js:8:21:8:39 | req.query.userInput | gemini_user_test.js:51:13:51:21 | userInput | This prompt construction depends on a $@. | gemini_user_test.js:8:21:8:39 | req.query.userInput | user-provided value | | gemini_user_test.js:58:13:58:21 | userInput | gemini_user_test.js:8:21:8:39 | req.query.userInput | gemini_user_test.js:58:13:58:21 | userInput | This prompt construction depends on a $@. | gemini_user_test.js:8:21:8:39 | req.query.userInput | user-provided value | +| gemini_user_test.js:66:17:66:25 | userInput | gemini_user_test.js:8:21:8:39 | req.query.userInput | gemini_user_test.js:66:17:66:25 | userInput | This prompt construction depends on a $@. | gemini_user_test.js:8:21:8:39 | req.query.userInput | user-provided value | | langchain_user_test.js:18:26:18:34 | userInput | langchain_user_test.js:13:21:13:39 | req.query.userInput | langchain_user_test.js:18:26:18:34 | userInput | This prompt construction depends on a $@. | langchain_user_test.js:13:21:13:39 | req.query.userInput | user-provided value | | langchain_user_test.js:22:26:22:34 | userInput | langchain_user_test.js:13:21:13:39 | req.query.userInput | langchain_user_test.js:22:26:22:34 | userInput | This prompt construction depends on a $@. | langchain_user_test.js:13:21:13:39 | req.query.userInput | user-provided value | | langchain_user_test.js:26:24:26:32 | userInput | langchain_user_test.js:13:21:13:39 | req.query.userInput | langchain_user_test.js:26:24:26:32 | userInput | This prompt construction depends on a $@. | langchain_user_test.js:13:21:13:39 | req.query.userInput | user-provided value | @@ -31,15 +33,19 @@ | openai_user_test.js:67:13:67:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:67:13:67:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | | openai_user_test.js:72:13:72:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:72:13:72:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | | openai_user_test.js:76:13:76:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:76:13:76:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | -| openai_user_test.js:83:13:83:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:83:13:83:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | -| openai_user_test.js:89:13:89:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:89:13:89:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | -| openai_user_test.js:95:14:95:22 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:95:14:95:22 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | -| openai_user_test.js:101:12:101:20 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:101:12:101:20 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | -| openai_user_test.js:148:12:148:20 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:148:12:148:20 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | -| openai_user_test.js:192:20:192:28 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:192:20:192:28 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | -| openai_user_test.js:196:30:196:38 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:196:30:196:38 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | -| openai_user_test.js:201:27:201:35 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:201:27:201:35 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | -| openai_user_test.js:205:30:205:38 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:205:30:205:38 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:82:13:82:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:82:13:82:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:86:13:86:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:86:13:86:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:90:13:90:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:90:13:90:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:96:13:96:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:96:13:96:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:103:13:103:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:103:13:103:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:109:13:109:21 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:109:13:109:21 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:115:14:115:22 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:115:14:115:22 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:121:12:121:20 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:121:12:121:20 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:168:12:168:20 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:168:12:168:20 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:212:20:212:28 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:212:20:212:28 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:216:30:216:38 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:216:30:216:38 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:221:27:221:35 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:221:27:221:35 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | +| openai_user_test.js:225:30:225:38 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:225:30:225:38 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | | openrouter_user_test.js:22:18:22:26 | userInput | openrouter_user_test.js:12:21:12:39 | req.query.userInput | openrouter_user_test.js:22:18:22:26 | userInput | This prompt construction depends on a $@. | openrouter_user_test.js:12:21:12:39 | req.query.userInput | user-provided value | | openrouter_user_test.js:36:19:36:27 | userInput | openrouter_user_test.js:12:21:12:39 | req.query.userInput | openrouter_user_test.js:36:19:36:27 | userInput | This prompt construction depends on a $@. | openrouter_user_test.js:12:21:12:39 | req.query.userInput | user-provided value | | openrouter_user_test.js:50:18:50:26 | userInput | openrouter_user_test.js:12:21:12:39 | req.query.userInput | openrouter_user_test.js:50:18:50:26 | userInput | This prompt construction depends on a $@. | openrouter_user_test.js:12:21:12:39 | req.query.userInput | user-provided value | @@ -51,13 +57,16 @@ edges | anthropic_user_test.js:8:9:8:17 | userInput | anthropic_user_test.js:18:18:18:26 | userInput | provenance | | | anthropic_user_test.js:8:9:8:17 | userInput | anthropic_user_test.js:31:18:31:26 | userInput | provenance | | +| anthropic_user_test.js:8:9:8:17 | userInput | anthropic_user_test.js:41:27:41:35 | userInput | provenance | | | anthropic_user_test.js:8:21:8:39 | req.query.userInput | anthropic_user_test.js:8:9:8:17 | userInput | provenance | | +| anthropic_user_test.js:41:27:41:35 | userInput | anthropic_user_test.js:41:13:41:51 | `\\n\\nHu ... stant:` | provenance | | | gemini_user_test.js:8:9:8:17 | userInput | gemini_user_test.js:14:15:14:23 | userInput | provenance | | | gemini_user_test.js:8:9:8:17 | userInput | gemini_user_test.js:26:19:26:27 | userInput | provenance | | | gemini_user_test.js:8:9:8:17 | userInput | gemini_user_test.js:37:15:37:23 | userInput | provenance | | | gemini_user_test.js:8:9:8:17 | userInput | gemini_user_test.js:44:13:44:21 | userInput | provenance | | | gemini_user_test.js:8:9:8:17 | userInput | gemini_user_test.js:51:13:51:21 | userInput | provenance | | | gemini_user_test.js:8:9:8:17 | userInput | gemini_user_test.js:58:13:58:21 | userInput | provenance | | +| gemini_user_test.js:8:9:8:17 | userInput | gemini_user_test.js:66:17:66:25 | userInput | provenance | | | gemini_user_test.js:8:21:8:39 | req.query.userInput | gemini_user_test.js:8:9:8:17 | userInput | provenance | | | langchain_user_test.js:13:9:13:17 | userInput | langchain_user_test.js:18:26:18:34 | userInput | provenance | | | langchain_user_test.js:13:9:13:17 | userInput | langchain_user_test.js:22:26:22:34 | userInput | provenance | | @@ -84,15 +93,19 @@ edges | openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:67:13:67:21 | userInput | provenance | | | openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:72:13:72:21 | userInput | provenance | | | openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:76:13:76:21 | userInput | provenance | | -| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:83:13:83:21 | userInput | provenance | | -| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:89:13:89:21 | userInput | provenance | | -| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:95:14:95:22 | userInput | provenance | | -| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:101:12:101:20 | userInput | provenance | | -| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:148:12:148:20 | userInput | provenance | | -| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:192:20:192:28 | userInput | provenance | | -| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:196:30:196:38 | userInput | provenance | | -| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:201:27:201:35 | userInput | provenance | | -| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:205:30:205:38 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:82:13:82:21 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:86:13:86:21 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:90:13:90:21 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:96:13:96:21 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:103:13:103:21 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:109:13:109:21 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:115:14:115:22 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:121:12:121:20 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:168:12:168:20 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:212:20:212:28 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:216:30:216:38 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:221:27:221:35 | userInput | provenance | | +| openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:225:30:225:38 | userInput | provenance | | | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:15:9:15:17 | userInput | provenance | | | openrouter_user_test.js:12:9:12:17 | userInput | openrouter_user_test.js:22:18:22:26 | userInput | provenance | | | openrouter_user_test.js:12:9:12:17 | userInput | openrouter_user_test.js:36:19:36:27 | userInput | provenance | | @@ -108,6 +121,8 @@ nodes | anthropic_user_test.js:8:21:8:39 | req.query.userInput | semmle.label | req.query.userInput | | anthropic_user_test.js:18:18:18:26 | userInput | semmle.label | userInput | | anthropic_user_test.js:31:18:31:26 | userInput | semmle.label | userInput | +| anthropic_user_test.js:41:13:41:51 | `\\n\\nHu ... stant:` | semmle.label | `\\n\\nHu ... stant:` | +| anthropic_user_test.js:41:27:41:35 | userInput | semmle.label | userInput | | gemini_user_test.js:8:9:8:17 | userInput | semmle.label | userInput | | gemini_user_test.js:8:21:8:39 | req.query.userInput | semmle.label | req.query.userInput | | gemini_user_test.js:14:15:14:23 | userInput | semmle.label | userInput | @@ -116,6 +131,7 @@ nodes | gemini_user_test.js:44:13:44:21 | userInput | semmle.label | userInput | | gemini_user_test.js:51:13:51:21 | userInput | semmle.label | userInput | | gemini_user_test.js:58:13:58:21 | userInput | semmle.label | userInput | +| gemini_user_test.js:66:17:66:25 | userInput | semmle.label | userInput | | langchain_user_test.js:13:9:13:17 | userInput | semmle.label | userInput | | langchain_user_test.js:13:21:13:39 | req.query.userInput | semmle.label | req.query.userInput | | langchain_user_test.js:18:26:18:34 | userInput | semmle.label | userInput | @@ -144,15 +160,19 @@ nodes | openai_user_test.js:67:13:67:21 | userInput | semmle.label | userInput | | openai_user_test.js:72:13:72:21 | userInput | semmle.label | userInput | | openai_user_test.js:76:13:76:21 | userInput | semmle.label | userInput | -| openai_user_test.js:83:13:83:21 | userInput | semmle.label | userInput | -| openai_user_test.js:89:13:89:21 | userInput | semmle.label | userInput | -| openai_user_test.js:95:14:95:22 | userInput | semmle.label | userInput | -| openai_user_test.js:101:12:101:20 | userInput | semmle.label | userInput | -| openai_user_test.js:148:12:148:20 | userInput | semmle.label | userInput | -| openai_user_test.js:192:20:192:28 | userInput | semmle.label | userInput | -| openai_user_test.js:196:30:196:38 | userInput | semmle.label | userInput | -| openai_user_test.js:201:27:201:35 | userInput | semmle.label | userInput | -| openai_user_test.js:205:30:205:38 | userInput | semmle.label | userInput | +| openai_user_test.js:82:13:82:21 | userInput | semmle.label | userInput | +| openai_user_test.js:86:13:86:21 | userInput | semmle.label | userInput | +| openai_user_test.js:90:13:90:21 | userInput | semmle.label | userInput | +| openai_user_test.js:96:13:96:21 | userInput | semmle.label | userInput | +| openai_user_test.js:103:13:103:21 | userInput | semmle.label | userInput | +| openai_user_test.js:109:13:109:21 | userInput | semmle.label | userInput | +| openai_user_test.js:115:14:115:22 | userInput | semmle.label | userInput | +| openai_user_test.js:121:12:121:20 | userInput | semmle.label | userInput | +| openai_user_test.js:168:12:168:20 | userInput | semmle.label | userInput | +| openai_user_test.js:212:20:212:28 | userInput | semmle.label | userInput | +| openai_user_test.js:216:30:216:38 | userInput | semmle.label | userInput | +| openai_user_test.js:221:27:221:35 | userInput | semmle.label | userInput | +| openai_user_test.js:225:30:225:38 | userInput | semmle.label | userInput | | openrouter_user_test.js:12:9:12:17 | userInput | semmle.label | userInput | | openrouter_user_test.js:12:21:12:39 | req.query.userInput | semmle.label | req.query.userInput | | openrouter_user_test.js:22:18:22:26 | userInput | semmle.label | userInput | diff --git a/javascript/ql/test/Security/CWE-1427/UserPromptInjection/anthropic_user_test.js b/javascript/ql/test/Security/CWE-1427/UserPromptInjection/anthropic_user_test.js index 1c269b650beb..a0c9514aa0e8 100644 --- a/javascript/ql/test/Security/CWE-1427/UserPromptInjection/anthropic_user_test.js +++ b/javascript/ql/test/Security/CWE-1427/UserPromptInjection/anthropic_user_test.js @@ -33,6 +33,14 @@ app.get("/test", async (req, res) => { ], }); + // === Legacy Text Completions API (SHOULD ALERT) === + + await client.completions.create({ + model: "claude-2.1", + max_tokens_to_sample: 1024, + prompt: `\n\nHuman: ${userInput}\n\nAssistant:`, // $ Alert[js/user-prompt-injection] + }); + // === Constant comparison sanitizer (SHOULD NOT ALERT) === const userInput2 = req.query.userInput2; diff --git a/javascript/ql/test/Security/CWE-1427/UserPromptInjection/gemini_user_test.js b/javascript/ql/test/Security/CWE-1427/UserPromptInjection/gemini_user_test.js index f38da3a418c9..32ed4299575a 100644 --- a/javascript/ql/test/Security/CWE-1427/UserPromptInjection/gemini_user_test.js +++ b/javascript/ql/test/Security/CWE-1427/UserPromptInjection/gemini_user_test.js @@ -58,6 +58,15 @@ app.get("/test", async (req, res) => { prompt: userInput, // $ Alert[js/user-prompt-injection] }); + // === caches.create: config.contents (SHOULD ALERT) === + + await ai.caches.create({ + model: "gemini-2.0-flash", + config: { + contents: userInput, // $ Alert[js/user-prompt-injection] + }, + }); + // === Constant comparison sanitizer (SHOULD NOT ALERT) === const userInput2 = req.query.userInput2; diff --git a/javascript/ql/test/Security/CWE-1427/UserPromptInjection/openai_user_test.js b/javascript/ql/test/Security/CWE-1427/UserPromptInjection/openai_user_test.js index 98e9dfcf6dc6..f4240679d7d0 100644 --- a/javascript/ql/test/Security/CWE-1427/UserPromptInjection/openai_user_test.js +++ b/javascript/ql/test/Security/CWE-1427/UserPromptInjection/openai_user_test.js @@ -76,6 +76,26 @@ app.get("/test", async (req, res) => { prompt: userInput, // $ Alert[js/user-prompt-injection] }); + // Videos API (Sora) + await client.videos.create({ + model: "sora-2", + prompt: userInput, // $ Alert[js/user-prompt-injection] + }); + + await client.videos.edit({ + prompt: userInput, // $ Alert[js/user-prompt-injection] + }); + + await client.videos.remix("video_123", { + prompt: userInput, // $ Alert[js/user-prompt-injection] + }); + + await client.videos.extend({ + video: { id: "video_123" }, + seconds: 4, + prompt: userInput, // $ Alert[js/user-prompt-injection] + }); + // Audio API await client.audio.transcriptions.create({ file: "audio.mp3",