From 5ef09a102c39770cbc4e7ab0ca8ffa32c9abe344 Mon Sep 17 00:00:00 2001 From: BazookaMusic Date: Fri, 15 May 2026 12:49:36 +0200 Subject: [PATCH] add tests for langchain and remove wrong model for guardrails agent --- javascript/ql/lib/ext/openai.model.yml | 2 + .../semmle/javascript/frameworks/OpenAI.qll | 7 +- .../SystemPromptInjection.expected | 18 +++ .../SystemPromptInjection/langchain_test.js | 50 +++++++++ .../UserPromptInjection.expected | 54 +++++++++ .../langchain_user_test.js | 106 ++++++++++++++++++ 6 files changed, 232 insertions(+), 5 deletions(-) create mode 100644 javascript/ql/test/experimental/Security/CWE-1427/SystemPromptInjection/langchain_test.js create mode 100644 javascript/ql/test/experimental/Security/CWE-1427/UserPromptInjection/langchain_user_test.js diff --git a/javascript/ql/lib/ext/openai.model.yml b/javascript/ql/lib/ext/openai.model.yml index 0c610d00977..2f0b41f50ca 100644 --- a/javascript/ql/lib/ext/openai.model.yml +++ b/javascript/ql/lib/ext/openai.model.yml @@ -21,3 +21,5 @@ extensions: - ["@openai/agents", "Member[tool].Argument[0].Member[description]", "system-prompt-injection"] - ["@openai/guardrails", "Member[tool].Argument[0].Member[description]", "system-prompt-injection"] - ["@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"] diff --git a/javascript/ql/src/experimental/semmle/javascript/frameworks/OpenAI.qll b/javascript/ql/src/experimental/semmle/javascript/frameworks/OpenAI.qll index 157702c3b64..b544ced00ab 100644 --- a/javascript/ql/src/experimental/semmle/javascript/frameworks/OpenAI.qll +++ b/javascript/ql/src/experimental/semmle/javascript/frameworks/OpenAI.qll @@ -243,13 +243,10 @@ module AgentSDK { } /** - * Gets user prompt sinks for run(agent, input). - * Covers string input and user-role array messages. + * Gets role-filtered user prompt sinks for run(agent, input). + * The string-input case is handled via MaD (openai.model.yml). */ API::Node getUserPromptNode() { - // run(agent, "string") — string input is the user prompt - result = run().getParameter(1) - or // run(agent, [{ role: "user", content: ... }]) exists(API::Node msg | msg = run().getParameter(1).getArrayElement() and diff --git a/javascript/ql/test/experimental/Security/CWE-1427/SystemPromptInjection/SystemPromptInjection.expected b/javascript/ql/test/experimental/Security/CWE-1427/SystemPromptInjection/SystemPromptInjection.expected index 514798e13c0..1f844f318f0 100644 --- a/javascript/ql/test/experimental/Security/CWE-1427/SystemPromptInjection/SystemPromptInjection.expected +++ b/javascript/ql/test/experimental/Security/CWE-1427/SystemPromptInjection/SystemPromptInjection.expected @@ -65,6 +65,13 @@ 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 | | +| 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 | | +| langchain_test.js:9:19:9:35 | req.query.persona | langchain_test.js:9:9:9:15 | persona | provenance | | +| langchain_test.js:16:54:16:60 | persona | langchain_test.js:16:37:16:60 | "Talk l ... persona | provenance | | +| langchain_test.js:19:31:19:37 | persona | langchain_test.js:19:14:19:37 | "Talk l ... persona | provenance | | +| langchain_test.js:25:36:25:42 | persona | langchain_test.js:25:19:25:42 | "Talk l ... persona | provenance | | | openai_test.js:11:9:11:15 | persona | openai_test.js:19:36:19:42 | persona | provenance | | | openai_test.js:11:9:11:15 | persona | openai_test.js:29:35:29:41 | persona | provenance | | | openai_test.js:11:9:11:15 | persona | openai_test.js:44:35:44:41 | persona | provenance | | @@ -154,6 +161,14 @@ 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 | +| 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 | +| langchain_test.js:16:54:16:60 | persona | semmle.label | persona | +| langchain_test.js:19:14:19:37 | "Talk l ... persona | semmle.label | "Talk l ... persona | +| langchain_test.js:19:31:19:37 | persona | semmle.label | persona | +| langchain_test.js:25:19:25:42 | "Talk l ... persona | semmle.label | "Talk l ... persona | +| langchain_test.js:25:36:25:42 | persona | semmle.label | persona | | openai_test.js:11:9:11:15 | persona | semmle.label | persona | | openai_test.js:11:19:11:35 | req.query.persona | semmle.label | req.query.persona | | openai_test.js:19:19:19:42 | "Talk l ... persona | semmle.label | "Talk l ... persona | @@ -206,6 +221,9 @@ subpaths | 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 prompt construction 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 prompt construction 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 prompt construction 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 prompt construction 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 prompt construction 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 prompt construction depends on a $@. | langchain_test.js:9:19:9:35 | req.query.persona | user-provided value | | openai_test.js:19:19:19:42 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:19:19:19:42 | "Talk l ... persona | This prompt construction depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | | openai_test.js:29:18:29:41 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:29:18:29:41 | "Talk l ... persona | This prompt construction depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | | openai_test.js:44:18:44:41 | "Talk l ... persona | openai_test.js:11:19:11:35 | req.query.persona | openai_test.js:44:18:44:41 | "Talk l ... persona | This prompt construction depends on a $@. | openai_test.js:11:19:11:35 | req.query.persona | user-provided value | diff --git a/javascript/ql/test/experimental/Security/CWE-1427/SystemPromptInjection/langchain_test.js b/javascript/ql/test/experimental/Security/CWE-1427/SystemPromptInjection/langchain_test.js new file mode 100644 index 00000000000..2259ccbf9ad --- /dev/null +++ b/javascript/ql/test/experimental/Security/CWE-1427/SystemPromptInjection/langchain_test.js @@ -0,0 +1,50 @@ +const express = require("express"); +const { ChatOpenAI } = require("@langchain/openai"); +const { HumanMessage, SystemMessage } = require("@langchain/core/messages"); +const { createAgent } = require("langchain"); + +const app = express(); + +app.get("/test", async (req, res) => { + const persona = req.query.persona; + const query = req.query.query; + + const chatModel = new ChatOpenAI({ model: "gpt-4" }); + + // === SystemMessage (SHOULD ALERT) === + + const sysMsg1 = new SystemMessage("Talk like a " + persona); // $ Alert[js/prompt-injection] + + const sysMsg2 = new SystemMessage({ + content: "Talk like a " + persona, // $ Alert[js/prompt-injection] + }); + + // === createAgent with systemPrompt (SHOULD ALERT) === + + const agent = createAgent({ + systemPrompt: "Talk like a " + persona, // $ Alert[js/prompt-injection] + }); + + // === Barrier test: user role content in shared array (SHOULD NOT ALERT) === + // When user input goes into a HumanMessage alongside a SystemMessage, + // the system prompt query should NOT alert on the HumanMessage content. + + await chatModel.invoke([ + new SystemMessage("You are a helpful assistant"), + new HumanMessage({ role: "user", content: query }), // OK - user role content is not a system prompt + ]); + + // Same pattern with raw message objects passed to invoke + await chatModel.invoke([ + { role: "system", content: "You are a helpful assistant" }, + { role: "user", content: query }, // OK - user role content blocked by barrier + ]); + + // === Constant comparison sanitizer (SHOULD NOT ALERT) === + + if (persona === "pirate") { + const sysMsg3 = new SystemMessage("Talk like a " + persona); // OK - sanitized + } + + res.send("done"); +}); diff --git a/javascript/ql/test/experimental/Security/CWE-1427/UserPromptInjection/UserPromptInjection.expected b/javascript/ql/test/experimental/Security/CWE-1427/UserPromptInjection/UserPromptInjection.expected index c460f0eba06..b44d68b2e8d 100644 --- a/javascript/ql/test/experimental/Security/CWE-1427/UserPromptInjection/UserPromptInjection.expected +++ b/javascript/ql/test/experimental/Security/CWE-1427/UserPromptInjection/UserPromptInjection.expected @@ -9,6 +9,24 @@ edges | 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: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 | | +| langchain_user_test.js:13:9:13:17 | userInput | langchain_user_test.js:26:24:26:32 | userInput | provenance | | +| langchain_user_test.js:13:9:13:17 | userInput | langchain_user_test.js:30:27:30:35 | userInput | provenance | | +| langchain_user_test.js:13:9:13:17 | userInput | langchain_user_test.js:34:26:34:34 | userInput | provenance | | +| langchain_user_test.js:13:9:13:17 | userInput | langchain_user_test.js:38:30:38:38 | userInput | provenance | | +| langchain_user_test.js:13:9:13:17 | userInput | langchain_user_test.js:42:33:42:41 | userInput | provenance | | +| langchain_user_test.js:13:9:13:17 | userInput | langchain_user_test.js:44:44:44:52 | userInput | provenance | | +| langchain_user_test.js:13:9:13:17 | userInput | langchain_user_test.js:49:31:49:39 | userInput | provenance | | +| langchain_user_test.js:13:9:13:17 | userInput | langchain_user_test.js:54:29:54:37 | userInput | provenance | | +| langchain_user_test.js:13:9:13:17 | userInput | langchain_user_test.js:59:34:59:42 | userInput | provenance | | +| langchain_user_test.js:13:9:13:17 | userInput | langchain_user_test.js:65:27:65:35 | userInput | provenance | | +| langchain_user_test.js:13:9:13:17 | userInput | langchain_user_test.js:71:27:71:35 | userInput | provenance | | +| langchain_user_test.js:13:9:13:17 | userInput | langchain_user_test.js:77:29:77:37 | userInput | provenance | | +| langchain_user_test.js:13:9:13:17 | userInput | langchain_user_test.js:81:31:81:39 | userInput | provenance | | +| langchain_user_test.js:13:9:13:17 | userInput | langchain_user_test.js:85:37:85:45 | userInput | provenance | | +| langchain_user_test.js:13:9:13:17 | userInput | langchain_user_test.js:90:21:90:29 | userInput | provenance | | +| langchain_user_test.js:13:21:13:39 | req.query.userInput | langchain_user_test.js:13:9:13:17 | userInput | provenance | | | openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:23:12:23:20 | userInput | provenance | | | openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:32:18:32:26 | userInput | provenance | | | openai_user_test.js:15:9:15:17 | userInput | openai_user_test.js:43:18:43:26 | userInput | provenance | | @@ -39,6 +57,25 @@ 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 | +| 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 | +| langchain_user_test.js:22:26:22:34 | userInput | semmle.label | userInput | +| langchain_user_test.js:26:24:26:32 | userInput | semmle.label | userInput | +| langchain_user_test.js:30:27:30:35 | userInput | semmle.label | userInput | +| langchain_user_test.js:34:26:34:34 | userInput | semmle.label | userInput | +| langchain_user_test.js:38:30:38:38 | userInput | semmle.label | userInput | +| langchain_user_test.js:42:33:42:41 | userInput | semmle.label | userInput | +| langchain_user_test.js:44:44:44:52 | userInput | semmle.label | userInput | +| langchain_user_test.js:49:31:49:39 | userInput | semmle.label | userInput | +| langchain_user_test.js:54:29:54:37 | userInput | semmle.label | userInput | +| langchain_user_test.js:59:34:59:42 | userInput | semmle.label | userInput | +| langchain_user_test.js:65:27:65:35 | userInput | semmle.label | userInput | +| langchain_user_test.js:71:27:71:35 | userInput | semmle.label | userInput | +| langchain_user_test.js:77:29:77:37 | userInput | semmle.label | userInput | +| langchain_user_test.js:81:31:81:39 | userInput | semmle.label | userInput | +| langchain_user_test.js:85:37:85:45 | userInput | semmle.label | userInput | +| langchain_user_test.js:90:21:90:29 | userInput | semmle.label | userInput | | openai_user_test.js:15:9:15:17 | userInput | semmle.label | userInput | | openai_user_test.js:15:21:15:39 | req.query.userInput | semmle.label | req.query.userInput | | openai_user_test.js:23:12:23:20 | userInput | semmle.label | userInput | @@ -67,6 +104,23 @@ subpaths | 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 | +| 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 | +| langchain_user_test.js:30:27:30:35 | userInput | langchain_user_test.js:13:21:13:39 | req.query.userInput | langchain_user_test.js:30:27:30:35 | 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:34:26:34:34 | userInput | langchain_user_test.js:13:21:13:39 | req.query.userInput | langchain_user_test.js:34:26:34: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:38:30:38:38 | userInput | langchain_user_test.js:13:21:13:39 | req.query.userInput | langchain_user_test.js:38:30:38:38 | 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:42:33:42:41 | userInput | langchain_user_test.js:13:21:13:39 | req.query.userInput | langchain_user_test.js:42:33:42:41 | 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:44:44:44:52 | userInput | langchain_user_test.js:13:21:13:39 | req.query.userInput | langchain_user_test.js:44:44:44:52 | 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:49:31:49:39 | userInput | langchain_user_test.js:13:21:13:39 | req.query.userInput | langchain_user_test.js:49:31:49:39 | 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:54:29:54:37 | userInput | langchain_user_test.js:13:21:13:39 | req.query.userInput | langchain_user_test.js:54:29:54:37 | 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:59:34:59:42 | userInput | langchain_user_test.js:13:21:13:39 | req.query.userInput | langchain_user_test.js:59:34:59:42 | 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:65:27:65:35 | userInput | langchain_user_test.js:13:21:13:39 | req.query.userInput | langchain_user_test.js:65:27:65:35 | 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:71:27:71:35 | userInput | langchain_user_test.js:13:21:13:39 | req.query.userInput | langchain_user_test.js:71:27:71:35 | 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:77:29:77:37 | userInput | langchain_user_test.js:13:21:13:39 | req.query.userInput | langchain_user_test.js:77:29:77:37 | 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:81:31:81:39 | userInput | langchain_user_test.js:13:21:13:39 | req.query.userInput | langchain_user_test.js:81:31:81:39 | 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:85:37:85:45 | userInput | langchain_user_test.js:13:21:13:39 | req.query.userInput | langchain_user_test.js:85:37:85:45 | 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:90:21:90:29 | userInput | langchain_user_test.js:13:21:13:39 | req.query.userInput | langchain_user_test.js:90:21:90:29 | userInput | This prompt construction depends on a $@. | langchain_user_test.js:13:21:13:39 | req.query.userInput | user-provided value | | openai_user_test.js:23:12:23:20 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:23:12:23: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:32:18:32:26 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:32:18:32:26 | 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:43:18:43:26 | userInput | openai_user_test.js:15:21:15:39 | req.query.userInput | openai_user_test.js:43:18:43:26 | userInput | This prompt construction depends on a $@. | openai_user_test.js:15:21:15:39 | req.query.userInput | user-provided value | diff --git a/javascript/ql/test/experimental/Security/CWE-1427/UserPromptInjection/langchain_user_test.js b/javascript/ql/test/experimental/Security/CWE-1427/UserPromptInjection/langchain_user_test.js new file mode 100644 index 00000000000..3cb06aed74a --- /dev/null +++ b/javascript/ql/test/experimental/Security/CWE-1427/UserPromptInjection/langchain_user_test.js @@ -0,0 +1,106 @@ +const express = require("express"); +const { ChatOpenAI } = require("@langchain/openai"); +const { ChatAnthropic } = require("@langchain/anthropic"); +const { HumanMessage, SystemMessage } = require("@langchain/core/messages"); +const { AgentExecutor } = require("langchain/agents"); +const { LLMChain } = require("langchain/chains"); +const { ChatPromptTemplate, PromptTemplate } = require("@langchain/core/prompts"); +const { createAgent, initChatModel } = require("langchain"); + +const app = express(); + +app.get("/test", async (req, res) => { + const userInput = req.query.userInput; + + // === ChatModel.invoke (SHOULD ALERT) === + + const chatModel = new ChatOpenAI({ model: "gpt-4" }); + await chatModel.invoke(userInput); // $ Alert[js/user-prompt-injection] + + // === ChatModel.stream (SHOULD ALERT) === + + await chatModel.stream(userInput); // $ Alert[js/user-prompt-injection] + + // === ChatModel.call (SHOULD ALERT) === + + await chatModel.call(userInput); // $ Alert[js/user-prompt-injection] + + // === ChatModel.predict (SHOULD ALERT) === + + await chatModel.predict(userInput); // $ Alert[js/user-prompt-injection] + + // === ChatModel.batch (SHOULD ALERT) === + + await chatModel.batch([userInput]); // $ Alert[js/user-prompt-injection] + + // === ChatModel.generate (SHOULD ALERT) === + + await chatModel.generate([[userInput]]); // $ Alert[js/user-prompt-injection] + + // === HumanMessage (SHOULD ALERT) === + + const msg1 = new HumanMessage(userInput); // $ Alert[js/user-prompt-injection] + + const msg2 = new HumanMessage({ content: userInput }); // $ Alert[js/user-prompt-injection] + + // === ChatAnthropic via type model (SHOULD ALERT) === + + const anthropicModel = new ChatAnthropic({ model: "claude-sonnet-4-20250514" }); + await anthropicModel.invoke(userInput); // $ Alert[js/user-prompt-injection] + + // === initChatModel via type model (SHOULD ALERT) === + + const dynamicModel = await initChatModel(); + await dynamicModel.invoke(userInput); // $ Alert[js/user-prompt-injection] + + // === AgentExecutor.invoke (SHOULD ALERT) === + + const executor = new AgentExecutor(); + await executor.invoke({ input: userInput }); // $ Alert[js/user-prompt-injection] + + // === createAgent().invoke with messages (SHOULD ALERT) === + + const agent = createAgent(); + await agent.invoke({ + messages: [{ content: userInput }], // $ Alert[js/user-prompt-injection] + }); + + // === createAgent().stream with messages (SHOULD ALERT) === + + await agent.stream({ + messages: [{ content: userInput }], // $ Alert[js/user-prompt-injection] + }); + + // === LLMChain.call (SHOULD ALERT) === + + const chain = new LLMChain(); + await chain.call({ input: userInput }); // $ Alert[js/user-prompt-injection] + + // === LLMChain.invoke (SHOULD ALERT) === + + await chain.invoke({ input: userInput }); // $ Alert[js/user-prompt-injection] + + // === ChatPromptTemplate.fromMessages (SHOULD ALERT) === + + ChatPromptTemplate.fromMessages([[userInput]]); // $ Alert[js/user-prompt-injection] + + // === PromptTemplate.format (SHOULD ALERT) === + + const tmpl = new PromptTemplate(); + await tmpl.format(userInput); // $ Alert[js/user-prompt-injection] + + // === SystemMessage should NOT alert for user-prompt-injection === + + const sysMsg = new SystemMessage(userInput); // OK - system prompt sink, not user prompt + + const sysMsg2 = new SystemMessage({ content: userInput }); // OK - system prompt sink + + // === Constant comparison sanitizer (SHOULD NOT ALERT) === + + const userInput2 = req.query.userInput2; + if (userInput2 === "hello") { + await chatModel.invoke(userInput2); // OK - sanitized by constant comparison + } + + res.send("done"); +});