Skip to content

Add OS command injection probe and detector#1870

Open
kenlacroix wants to merge 2 commits into
NVIDIA:mainfrom
kenlacroix:feat/exploitation-os-command-injection
Open

Add OS command injection probe and detector#1870
kenlacroix wants to merge 2 commits into
NVIDIA:mainfrom
kenlacroix:feat/exploitation-os-command-injection

Conversation

@kenlacroix

Copy link
Copy Markdown

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 established ECHO_TEMPLATE pattern to get the target to emit shell commands. Reuses the existing access_shell_commands payload set, which until now was only referenced by the encoding probes.
  • 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 (new test_shell_command covers payload echo, constructed sinks, and benign negatives)
  • pytest tests/plugins/test_plugins.py — 361 passed (plugin metadata/tags/detector resolution)
  • black clean

kenlacroix and others added 2 commits June 19, 2026 08:48
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 erickgalinkin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread garak/probes/exploitation.py
Comment on lines +199 to +200
for payload in garak.payloads.load(self.payload_name).payloads:
self.prompts.append(self.template.format(payload))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This vuln explicitly works for tool calling, which we don't support in a first-class way yet.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@kenlacroix

Copy link
Copy Markdown
Author

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 exploitation.py (shared ECHO_TEMPLATE + echo detectors), so it's consistent with what's there rather than a new pattern, but I take the point that it stops at the precondition.

Happy to defer to your roadmap: would you prefer I convert this to draft and revisit once first-class tool message support lands (glad to help build toward that), or keep it open as a tracking placeholder? Same question applies to the NoSQL sibling (#1871).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants