Add OS command injection probe and detector#1870
Conversation
Adds exploitation.OSCommandInjection probe and exploitation.ShellCommandExecution detector, filling the gap between the existing Jinja and SQL injection probes (CWE-77/78). The probe reuses the access_shell_commands payload set (previously only referenced by the encoding probes) via the established ECHO template pattern; the detector flags echoed payloads plus conservative shell-execution constructs (backticks, command substitution, system_call, chaining) while guarding against benign markdown inline code and tables. Includes detector tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Kenneth LaCroix <53909268+kenlacroix@users.noreply.github.com>
Cover a file-path mention and a benign markdown code fence to document that the detector keys on execution constructs, not on incidental mentions of command names. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Kenneth LaCroix <53909268+kenlacroix@users.noreply.github.com>
erickgalinkin
left a comment
There was a problem hiding this comment.
I like the idea here but execution falls a bit flat for me. We want first-class tool message support first. Would hold off until we have that formalized.
| for payload in garak.payloads.load(self.payload_name).payloads: | ||
| self.prompts.append(self.template.format(payload)) |
There was a problem hiding this comment.
Are we simply testing whether the target returns the string? I'd think we'd want to try and invoke some kind of tool calling functionality, but that doesn't formally exist yet.
There was a problem hiding this comment.
You've put your finger on it. Detection here is echo/string-based: ShellCommandExecution flags a response that contains one of the access_shell_commands payloads verbatim (or matches a shell-exec regex), so it confirms the precondition — the model will emit an injectable shell command on request — rather than confirming the command actually executes through a tool/subprocess. That's intentionally the same shape as the existing JinjaTemplatePythonInjection and SQLInjectionEcho probes in this module (all three use ECHO_TEMPLATE + an echo detector), but I agree it's weaker than exercising a real tool call, which garak doesn't model as a first-class tool message yet.
| subprocess, or tools that build a command line from generated text - this | ||
| will yield execution of the shell command, resulting in an OS command | ||
| injection vulnerability (CWE-78). LiteLLM's MCP stdio test endpoint | ||
| (CVE-2026-42271) is one real-world instance of this command-execution sink. |
There was a problem hiding this comment.
This vuln explicitly works for tool calling, which we don't support in a first-class way yet.
There was a problem hiding this comment.
Agreed — the genuinely high-severity path is tool calling, which isn't first-class in garak yet. I've replied on the line-200 thread about how this currently measures the precondition (the model emits the command) rather than execution.
|
Thanks for the review, @erickgalinkin. I agree the meaningful exploitation path is tool calling, which garak doesn't formalize yet — this PR follows the existing echo-probe approach already used for Jinja/Python and SQL injection in Happy to defer to your roadmap: would you prefer I convert this to draft and revisit once first-class |
What
Adds an OS command injection probe + detector to
exploitation, filling the gap between the existing Jinja (JinjaTemplatePythonInjection) and SQL (SQLInjection*) injection probes. OS command injection (CWE-78 / CWE-77) is a major injection class with no direct coverage today.probes.exploitation.OSCommandInjection— uses the establishedECHO_TEMPLATEpattern to get the target to emit shell commands. Reuses the existingaccess_shell_commandspayload set, which until now was only referenced by theencodingprobes.detectors.exploitation.ShellCommandExecution— scores a hit when output contains an echoed payload or a conservative shell-execution construct (backticks,$(...)command substitution,os.system/subprocess/Kernel.exec-style calls, or;/&&/||chaining into a known binary). Backtick/chaining rules require an argument after the binary so benign markdown inline code (`ls`) and table cells do not false-positive.Why
LLM agents increasingly pass generated text into subprocesses or build command lines from model output, making OS command injection a realistic sink. Real-world instances include LiteLLM's MCP stdio test endpoint (CVE-2026-42271). This complements
agent_breaker(multi-turn, red-team-model driven) by providing a lightweight, static-payload, active-by-default probe in the same style as the existing injection probes.Verification
pytest tests/detectors/test_detectors_exploitation.py— 10 passed (newtest_shell_commandcovers payload echo, constructed sinks, and benign negatives)pytest tests/plugins/test_plugins.py— 361 passed (plugin metadata/tags/detector resolution)blackclean