title: 'Argument Injection: Execution-Bearing CLI Option Smuggled into a Tool Data Parameter'
id: ATR-2026-02601
rule_version: 1
status: experimental
description: |
  Detects the argument-injection shape behind CVE-2026-25130 (CAI find_file): a value that a tool documents as DATA -- a filename, a glob, a search term, an args string -- begins with a dash and therefore reaches the underlying binary as an OPTION, and the option it reaches is one that executes a program. No shell metacharacter is involved anywhere, which is why the existing shell metacharacter rule ATR-2026-00111 stays silent on the whole family: verified against the engine, the same payload only fires 00111 once a pipe is added.
  WHAT MAKES IT PRECISE, AND WHAT THAT COSTS. `-exec` on its own is not the signal -- `find . -name "*.pyc" -exec rm -f {} \;` is a thing developers and agents legitimately do all day, and it appears in the find(1) manual, in Makefile lint targets and in CI logs. Three things have to line up before this rule fires: (a) the dash-leading value sits in a parameter NAMED as data (args/pattern/path/query/...; `command`, `cmd` and `script` are excluded because a shell tool is supposed to receive options), (b) the option is one with execution or file-write semantics, and (c) the thing it executes is an INTERPRETER or network client (sh, bash, python, perl, node, nc, curl, wget) or lives in a world-writable scratch directory. `-exec rm`, `-exec chmod`, `-exec shellcheck`, `-exec gzip {} +` are all deliberately NOT claimed.
  The same three-part test is applied to the archive and transport options in the same family: tar --checkpoint-action=exec=, --to-command=, --use-compress-program=, unzip's --unzip-command=, rsync's --rsh=, and find's -fprintf aimed at a login/startup path. GNU tar's own manual example (--checkpoint-action=exec=/sbin/cdrom-eject) and rsync --rsh=ssh are measured true negatives; --checkpoint-action=exec=/tmp/stage.sh and --rsh=sh are not.
  NOT COVERED ON PURPOSE. `--upload-pack=` / `ext::` (git transport) and `--pre=` / `-oProxyCommand=` (ripgrep, ssh) belong to the same class but are left to rules scoped to those tools; folding every binary's option table into one regex would trade the precision above for a list nobody can review.
author: ATR Community
date: 2026/08/23
schema_version: '0.1'
detection_tier: pattern
maturity: test
severity: high
references:
  owasp_llm:
    - LLM06:2025
  owasp_agentic:
    - ASI03:2026
  mitre_atlas:
    - AML.T0053 - LLM Plugin Compromise
    - AML.T0051 - LLM Prompt Injection
  cve:
    - CVE-2026-25130
compliance:
  owasp_agentic:
    - id: ASI03:2026
      context: A tool the agent is authorised to use for reading files is turned into arbitrary command execution purely through the shape of its argument, which is privilege escalation without any new permission being granted.
      strength: primary
  owasp_llm:
    - id: LLM06:2025
      context: 'Excessive agency: the effective capability of a read-only tool exceeds what its schema and description advertise, and the gap is reachable from model-controlled input.'
      strength: primary
  eu_ai_act:
    - article: '15'
      context: 'Article 15 cybersecurity: the rule detects an input crafted so that a component interprets data as control, the canonical injection failure the article requires resilience against.'
      strength: primary
    - article: '9'
      context: Tool argument injection is a documented risk class for tool-using agents; detections are the monitoring output Article 9 risk management requires.
      strength: secondary
    - article: '14'
      context: A human overseeing a file-search tool cannot be expected to notice that its argument reaches -exec; surfacing the event is what makes the oversight in Article 14 effective.
      strength: secondary
  nist_ai_rmf:
    - function: Manage
      subcategory: MG.2.3
      context: Runtime treatment for the risk that an agent tool's real capability exceeds its declared one.
      strength: primary
    - function: Map
      subcategory: MP.5.1
      context: Catalogues option-smuggling as a distinct risk from shell-metacharacter injection, which existing controls already cover.
      strength: secondary
    - function: Measure
      subcategory: MS.2.7
      context: Detection events document the security and resilience of the tool boundary as MEASURE 2.7 requires.
      strength: secondary
  iso_42001:
    - clause: '8.1'
      context: 'Clause 8.1 operational control: the boundary between a tool''s data inputs and its control inputs is an operational control this rule verifies at runtime.'
      strength: primary
    - clause: '6.2'
      context: Preventing tool-mediated command execution is an AIMS information security objective under clause 6.2.
      strength: secondary
    - clause: '8.4'
      context: Impact assessment under 8.4 must account for third-party CLI binaries invoked on the agent's behalf; these events are the evidence for that path.
      strength: secondary
tags:
  category: privilege-escalation
  subcategory: argument-injection
  scan_target: both
  confidence: medium
agent_source:
  type: mcp_exchange
  framework:
    - any
  provider:
    - any
detection:
  conditions:
    - field: content
      operator: regex
      value: '["'']?(?:args?|arguments|argv|options?|opts|pattern|glob|name|filename|file_?name|path|filepath|dir|directory|query|search|search_?term|term|target|keyword|input|value|expr|expression)["'']?\s*[:=]\s*["'']\s{0,4}-[^"\n]{0,150}?\B-exec(?:dir)?\s+["'']?(?:[^"''\s]{0,40}/)?(?:sh|bash|zsh|dash|ksh|python\d?(?:\.\d+)?|perl|ruby|php|node|nc|ncat|netcat|curl|wget|osascript|powershell|pwsh)\b'
      description: Dash-leading data parameter whose value reaches find -exec/-execdir with an interpreter or network client
    - field: tool_args
      operator: regex
      value: '["'']?(?:args?|arguments|argv|options?|opts|pattern|glob|name|filename|file_?name|path|filepath|dir|directory|query|search|search_?term|term|target|keyword|input|value|expr|expression)["'']?\s*[:=]\s*["'']\s{0,4}-[^"\n]{0,150}?\B-exec(?:dir)?\s+["'']?(?:[^"''\s]{0,40}/)?(?:sh|bash|zsh|dash|ksh|python\d?(?:\.\d+)?|perl|ruby|php|node|nc|ncat|netcat|curl|wget|osascript|powershell|pwsh)\b'
      description: Same, in the JSON-encoded tool argument object
    - field: content
      operator: regex
      value: '["'']?(?:args?|arguments|argv|options?|opts|pattern|glob|name|filename|file_?name|path|filepath|dir|directory|query|search|search_?term|term|target|keyword|input|value|expr|expression)["'']?\s*[:=]\s*["'']\s{0,4}-[^"\n]{0,180}?-{0,2}(?:checkpoint-action\s*=\s*exec=?\s*(?:["'']?(?:[^"''\s]{0,40}/)?(?:sh|bash|zsh|dash|ksh|python\d?(?:\.\d+)?|perl|ruby|php|node|nc|ncat|netcat|curl|wget|osascript|powershell|pwsh)\b|["'']?(?:/tmp/|/var/tmp/|/dev/shm/|~/|\$HOME/))|to-command\s*=\s*(?:["'']?(?:[^"''\s]{0,40}/)?(?:sh|bash|zsh|dash|ksh|python\d?(?:\.\d+)?|perl|ruby|php|node|nc|ncat|netcat|curl|wget|osascript|powershell|pwsh)\b|["'']?(?:/tmp/|/var/tmp/|/dev/shm/|~/|\$HOME/))|use-compress-program\s*=\s*(?:["'']?(?:[^"''\s]{0,40}/)?(?:sh|bash|zsh|dash|ksh|python\d?(?:\.\d+)?|perl|ruby|php|node|nc|ncat|netcat|curl|wget|osascript|powershell|pwsh)\b|["'']?(?:/tmp/|/var/tmp/|/dev/shm/|~/|\$HOME/))|unzip-command\s*=\s*(?:["'']?(?:[^"''\s]{0,40}/)?(?:sh|bash|zsh|dash|ksh|python\d?(?:\.\d+)?|perl|ruby|php|node|nc|ncat|netcat|curl|wget|osascript|powershell|pwsh)\b|["'']?(?:/tmp/|/var/tmp/|/dev/shm/|~/|\$HOME/))|rsh\s*=\s*["'']?(?:[^"''\s]{0,40}/)?(?:sh|bash|zsh|dash|ksh|python\d?(?:\.\d+)?|perl|ruby|php|node|nc|ncat|netcat|curl|wget|osascript|powershell|pwsh)\b|fprintf?\s+["'']?(?:~|\$HOME|/home/|/root/|/etc/|/var/spool/cron))'
      description: Dash-leading data parameter carrying an archive/transport option that runs a program or writes a login file
    - field: tool_args
      operator: regex
      value: '["'']?(?:args?|arguments|argv|options?|opts|pattern|glob|name|filename|file_?name|path|filepath|dir|directory|query|search|search_?term|term|target|keyword|input|value|expr|expression)["'']?\s*[:=]\s*["'']\s{0,4}-[^"\n]{0,180}?-{0,2}(?:checkpoint-action\s*=\s*exec=?\s*(?:["'']?(?:[^"''\s]{0,40}/)?(?:sh|bash|zsh|dash|ksh|python\d?(?:\.\d+)?|perl|ruby|php|node|nc|ncat|netcat|curl|wget|osascript|powershell|pwsh)\b|["'']?(?:/tmp/|/var/tmp/|/dev/shm/|~/|\$HOME/))|to-command\s*=\s*(?:["'']?(?:[^"''\s]{0,40}/)?(?:sh|bash|zsh|dash|ksh|python\d?(?:\.\d+)?|perl|ruby|php|node|nc|ncat|netcat|curl|wget|osascript|powershell|pwsh)\b|["'']?(?:/tmp/|/var/tmp/|/dev/shm/|~/|\$HOME/))|use-compress-program\s*=\s*(?:["'']?(?:[^"''\s]{0,40}/)?(?:sh|bash|zsh|dash|ksh|python\d?(?:\.\d+)?|perl|ruby|php|node|nc|ncat|netcat|curl|wget|osascript|powershell|pwsh)\b|["'']?(?:/tmp/|/var/tmp/|/dev/shm/|~/|\$HOME/))|unzip-command\s*=\s*(?:["'']?(?:[^"''\s]{0,40}/)?(?:sh|bash|zsh|dash|ksh|python\d?(?:\.\d+)?|perl|ruby|php|node|nc|ncat|netcat|curl|wget|osascript|powershell|pwsh)\b|["'']?(?:/tmp/|/var/tmp/|/dev/shm/|~/|\$HOME/))|rsh\s*=\s*["'']?(?:[^"''\s]{0,40}/)?(?:sh|bash|zsh|dash|ksh|python\d?(?:\.\d+)?|perl|ruby|php|node|nc|ncat|netcat|curl|wget|osascript|powershell|pwsh)\b|fprintf?\s+["'']?(?:~|\$HOME|/home/|/root/|/etc/|/var/spool/cron))'
      description: Same, in the JSON-encoded tool argument object
  condition: any
  false_positives:
    - 'DEPRECATED 2026-08-23 BY ADVERSARIAL REVIEW. The find -exec branch cannot separate attack from benign inside a single event. Measured on the live engine: 30 of 40 realistic benign inputs fired, including the most-copied find recipe there is -- `-exec php -l`, `-exec python -m py_compile`, `-exec node --check`, `-exec ruby -c`, `-exec perl -c`, `-exec bash -n` -- and GNU findutils OWN recommended safe form, `-exec sh -c` / `-execdir sh -c`. Those strings are character-for-character the same shape as the declared true positives; what makes the real one an attack is that the parameter was model-controlled, and that fact is not in the event'
    - 'The one narrowing that cleared those FPs -- requiring the executed program to be reached by absolute path -- was measured and rejected as overfitting to the six declared true positives: with it applied, deleting the four characters `/bin/` from TP1, TP2 and TP3 evaded the rule entirely (all three went clean), as did `./sh`. It traded a measurable false-positive rate for a one-edit evasion'
    - 'Premise (a) of the rule, that the parameter is NAMED as data, does not hold. args/arguments/argv/options/opts are the canonical names for RAW ARGUMENT PASSTHROUGH. The rule''s own true negatives concede it: TN 3, 4 and 5 are all {tool: run_find, args: -... -exec ...} and are negative only because of the program name, never the parameter name. With (a) contributing nothing the rule reduces to `an interpreter name appears after -exec`, which is a keyword list'
    - The -fprintf branch claimed to detect a login/startup path but tested only the DIRECTORY PREFIX, so `-fprint /home/ci/build-manifest.txt`, `-fprintf /home/deploy/objects.txt`, `-fprintf ~/reports/changed.txt` and `-fprintf /root/suid-audit.txt` all fired on plain manifest generation. `fprintf?` also matches bare `-fprint`, which has no execution semantics at all
    - 'The claimed 13,246-sample 0 FP was a near-zero measurement: only 69 of the 12,830 samples in data/benign-corpus-extended contain `-exec` at any position, and 4 contain `fprint`. A skills/npm/pypi/arxiv corpus does not carry find command lines inside JSON tool calls, so it could not have charged this rule'
    - 'Fires on a detection project''s own rule and test files, e.g. a YAML line `value: ''-name x -exec /bin/sh -c id ;''`, because `value` is in the parameter-name list'
    - 'An awk BEGIN system() condition was authored, measured against the benign corpus, and REMOVED: it fired on three penetration-testing reference skills that quote GTFOBins one-liners. Inline interpreter code is a different shape from argument injection and did not belong in this rule'
    - 'An operations tool that deliberately exposes raw find/tar arguments and is genuinely asked to run an interpreter over the matches (measured: -exec rm / chmod / shellcheck / gzip do NOT fire; -exec /bin/sh does, by design)'
    - A backup script whose tar checkpoint action legitimately runs a helper staged in /tmp
    - Security writing that quotes the CVE-2026-25130 proof of concept inside a JSON tool call verbatim
response:
  actions:
    - alert
    - snapshot
  auto_response_threshold: high
  message_template: |
    [ATR-2026-02601] A tool parameter documented as data carries a dash-leading value that reaches an execution-bearing CLI option (find -exec, tar --checkpoint-action=exec, --to-command, rsync --rsh). No shell metacharacter is required for this to run code. Verify the value's origin before allowing the call.
confidence: 70
