T09 · Insecure Skill Coding Practices
- Location
scripts/search_jobs.sh:31- Finding
Arbitrary Code Execution Through Python Source Injection
- Content
View full analysis
/dev/null || echo "$ALL_RESULTS") ``` Finally, the user-controlled `--limit` value is inserted as an executable Python expression: ```bash # Trim to limit echo "$ALL_RESULTS" | python3 -c " import json, sys results = json.load(sys.stdin)[:${LIMIT}] print(json.dumps(results, indent=2)) " ``` ### Technical Analysis The script builds Python programs using shell-expanded strings and passes them to `python3 -c`. Values such as `QUERY`, `sq`, `ALL_RESULTS`, and `LIMIT` are treated as Python source code instead of data. Quoting the shell variable does not make interpolation into Python source safe. An attacker can include Python quote delimiters, statement separators, expressions, and comments in an argument. Once interpolated, these characters can terminate the intended string or slice expression and append arbitrary Python statements. The vulnerable data flows are: 1. The first positional command-line argument is assigned to `QUERY`. 2. `QUERY` is placed inside a s ...[truncated 4084 chars]- Remediation
View remediation
&2 exit 2 fi if [[ ! "$LIMIT" =~ ^[0-9]+$ ]]; then printf 'Error: --limit must be a non-negative integer\n' >&2 exit 2 fi ``` Pass the validated limit as an argument rather than interpolating it: ```bash echo "$ALL_RESULTS" | python3 -c ' import json import sys limit = int(sys.argv[1]) results = json.load(sys.stdin)[:limit] print(json.dumps(results, indent=2)) ' "$LIMIT" ``` A reasonable upper bound should also be enforced to prevent excessive resource consumption: ```bash if (( LIMIT > 100 )); then printf 'Error: --limit must not exceed 100\n' >&2 exit 2 fi ``` ### 3. Merge JSON without embedding it into source Provide both JSON documents through files, separate file descriptors, or arguments. A robust option is to use temporary files created securely: ```bash tmp_all=$(mktemp) tmp_parsed=$(mktemp) trap 'rm -f "$tmp_all" "$tmp_parsed"' EXIT printf '%s' "$ALL_RESULTS" > "$tmp_all" printf '%s' "$PARSED" > "$tmp_parsed" ALL_RESULTS=$( python3 - "$tmp_all" "$tmp_parsed" <<'PY' import json import sys with open(sys.argv[1], encoding="utf-8") as handle: existing = js ...[truncated 1134 chars]
