T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/filed.sh:131
- Finding
- Arbitrary Python Code Execution Through Unsafe Query Encoding<![CDATA[ ## Vulnerability Details **File Location**: `scripts/filed.sh`, lines 131–133 **Vulnerability Type**: User-controlled input embedded directly into dynamically interpreted Python source **Risk Level**: High ### Vulnerable Code ```bash [[ -n "$name" ]] && url+="&name=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$name'))" 2>/dev/null || echo "$name")" [[ -n "$agent" ]] && url+="&agent=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$agent'))" 2>/dev/null || echo "$agent")" [[ -n "$officer" ]] && url+="&officer=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$officer'))" 2>/dev/null || echo "$officer")" ``` ### Technical Analysis The values supplied through `--name`, `--agent`, and `--officer` are inserted directly into Python source code executed using `python3 -c`. Although the shell variables are expanded within a shell-quoted argument, the expanded result is subsequently interpreted as Python program text. An attacker can include a single quote in an option value to terminate the intended Python string literal, append arbitrary Python statements, and comment out the remaining generated source. For example, a value structurally equivalent to the following can escape the intended string: ```text '); __import__("os").system("ATTACKER_COMMAND"); # ``` This causes the dynamically constructed Python program to invoke an attacker-selected operating-system command rather than merely URL-encoding the supplied value. The issue affects all three query parameters processed in this manner. The fallback `|| echo "$name"` does not mitigate the vulnerability because injected commands can execute before `python3` exits. It also returns unencoded input when Python is unavailable or fails, which can produce malformed or attacker-influenced query strings. ### Attack Path 1. An attacker influences a value passed to `filed.sh search` through `--name`, `--agent`, or `--officer`. 2. The script interpolates that value into t ...[truncated 1381 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Do not interpolate user-controlled data into dynamically interpreted Python source. Pass each value as a separate positional argument: ```bash urlencode() { python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "$1" } [[ -n "$name" ]] && url+="&name=$(urlencode "$name")" [[ -n "$agent" ]] && url+="&agent=$(urlencode "$agent")" [[ -n "$officer" ]] && url+="&officer=$(urlencode "$officer")" ``` A preferable approach is to avoid constructing the query string manually and delegate encoding to `curl`: ```bash curl -sS --get "${BASE_URL}/search" \ --data-urlencode "state=${state}" \ --data-urlencode "name=${name}" \ -H "Authorization: Bearer ${API_KEY}" \ -H "Content-Type: application/json" ``` Add optional parameters only when they are present. This separates query data from executable code and consistently encodes reserved characters. Additional hardening should include: 1. Validate `state` against the explicitly supported state-code allowlist. 2. Validate enumerated fields such as `status` and `type`. 3. Validate dates, limits, and offsets against their documented formats and ranges. 4. Reject malformed command-line options and missing option values explicitly. 5. Remove the unsafe unencoded `echo` fallback; fail closed if the selected encoding mechanism is unavailable. 6. Add regression tests containing apostrophes, quotation marks, semicolons, command-substitution syntax, newlines, and Unicode characters. 7. Avoid exposing API keys through command-line arguments where possible; prefer the environment variable or another protected secret mechanism. ]]>
