T09 · Insecure Skill Coding Practices
- Location
scripts/poll-template.sh:17- Finding
Arbitrary Shell Command Execution Through Unsafe eval Usage
- Content
View full analysis
Vulnerability Details
File Location:
scripts/poll-template.sh, lines 17–25, 119, and 127
Vulnerability Type: Shell command injection
Risk Level: HighVulnerable Code
bash # Poll command — must return within seconds and produce parseable output POLL_COMMAND='echo "Replace this with the actual status check command"' # Output parsing: extract a value from POLL_COMMAND output # e.g., for JSON output '{"status": "completed"}', use: # jq -r '.status' <<< "$OUTPUT" # e.g., for plain text, use: # grep -o 'status: [a-z]*' | awk '{print $2}' PARSE_OUTPUT='jq -r ".status" <<< "$OUTPUT"'bash OUTPUT=$(eval "$POLL_COMMAND" 2>&1) || {bash PARSED=$(eval "$PARSE_OUTPUT" <<< "$OUTPUT" 2>/dev/null) || PARSED="parse_error"Technical Analysis
The template stores the polling operation and parsing logic as shell command strings, then executes both strings with
eval. Unlike direct command invocation,evalreparses its argument as shell source code. Consequently, shell metacharacters, command substitutions, redirections, pipelines, and additional commands contained in either configured value are interpreted and executed.The template instructs an agent to replace these values for each polling task but does not require allowlisting, validation, fixed parser selection, or safe argument-array construction. If an untrusted task request can influence
POLL_COMMANDorPARSE_OUTPUT, the resulting generated polling script becomes an arbitrary command-execution channel.Using quoted variables around
evaldoes not prevent injection because reparsing is the intended behavior ofeval.Attack Path
- An attacker requests polling of a status command or output rule containing embedded shell syntax.
- The agent incorporates the attacker-influenced text into
POLL_COMMANDorPARSE_OUTPUT. - Following the documented workflow, the generated polling script is launched in the back ...[truncated 1063 chars]
- Remediation
View remediation
Remediation Suggestions
- Remove both uses of
eval. - Represent executable commands as Bash arrays so arguments are not reparsed as shell syntax:
bash POLL_COMMAND=(status-tool status --id "$TASK_ID") if ! OUTPUT=$("${POLL_COMMAND[@]}" 2>&1); then log "Polling command failed" save_progress "$POLL_COUNT" "command_failed" sleep "$POLL_INTERVAL" continue fi- Implement parsing as a fixed function rather than a configurable shell expression:
bash parse_status() { jq -er '.status | strings' <<< "$1" } if ! PARSED=$(parse_status "$OUTPUT" 2>/dev/null); then PARSED="parse_error" fi- If multiple polling tools or parsing formats must be supported, select them through a strict allowlist of identifiers and dispatch to predefined functions. Do not accept arbitrary command text.
- Validate all externally influenced identifiers, paths, status values, and arguments according to narrow expected formats.
- Reject shell control syntax in legacy string-based configurations, including command substitutions, separators, redirections, and newline characters. This should be defense in depth rather than a substitute for eliminating
eval. - Execute polling jobs with least privilege, a restricted environment, minimal filesystem permissions, and only the network access required for the intended status endpoint.
- Add security tests demonstrating that values containing shell metacharacters are treated as literal arguments and cannot create files or execute secondary commands.
- Remove both uses of
