T09 · Insecure Skill Coding Practices
- Location
references/testing.md:17- Finding
Shell Command Injection Through Dynamic Command Evaluation
- Content
View full analysis
Vulnerability Details
File Location:
references/testing.md, lines 17–18
Vulnerability Type: Shell command injection througheval
Risk Level: HighVulnerable Code
bash # Smoke: every documented command must produce parseable JSON. for cmd in $(tool _internal list-commands); do out=$(eval "$cmd --dry-run" 2>/dev/null) || true echo "$out" | jq -e 'has("ok")' > /dev/null \ || { echo "FAIL: $cmd produced non-JSON or missing 'ok'"; exit 1; } doneTechnical Analysis
The test harness treats output from the CLI under test as trusted shell source code.
tool _internal list-commandsdetermines the strings assigned tocmd, andevalreparses each resulting string using the full shell grammar.If the reviewed CLI is malicious or compromised, it can include shell metacharacters, command substitutions, redirects, pipelines, or additional commands in its output. These constructs will execute with the privileges and environment of the person or CI runner performing the audit.
The command-substitution loop also applies shell word splitting and pathname expansion before
eval, making the behavior unsafe and unreliable even for benign command strings containing spaces or wildcard characters.Attack Path
- A developer or CI system applies the documented test harness to an untrusted CLI.
- The harness invokes
tool _internal list-commands. - The CLI returns attacker-controlled shell syntax as part of a purported command entry.
- The loop assigns that output to
cmd. eval "$cmd --dry-run"reparses the value as shell code.- The injected commands execute under the tester's account and inherit the test process's accessible environment and filesystem permissions.
Impact Assessment
Successful exploitation provides arbitrary command execution with the privileges of the user or CI runner executing the example. Depending on the surrounding environment, an attacker could:
- Read or modify files accessible to the te ...[truncated 457 chars]
- Remediation
View remediation
Remediation Suggestions
- Remove
evaland never interpret CLI-produced text as shell source code. - Make the internal discovery command return structured data, preferably JSON arrays containing an executable and separate arguments.
- Parse the output with
jqand invoke commands through Bash arrays so each argument remains data rather than syntax. - Alternatively, maintain a trusted, test-owned manifest of commands instead of accepting executable command lines from the program under test.
- Validate discovered executable and subcommand names against strict allowlists.
- Avoid
for cmd in $(...); use a format-preserving loop such aswhile IFS= read -rfor line data, although this alone does not make evaluation safe. - Run tests of untrusted CLIs in a sandbox with a minimal environment, read-only source mounts, no production credentials, and denied network access unless explicitly required.
A safer design is for discovery to emit argument arrays, for example:
bash tool _internal list-commands-json | jq -c '.[]' | while IFS= read -r entry; do mapfile -t argv < <(jq -r '.[]' <<<"$entry") out=$("${argv[@]}" --dry-run 2>/dev/null) || true jq -e 'has("ok")' <<<"$out" >/dev/null || { echo "FAIL: command produced non-JSON or missing 'ok'" >&2; exit 1; } doneThe exact implementation should ensure that no value originating from the reviewed CLI is reparsed as shell syntax.
- Remove
