T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/script.sh:64
- Finding
- Python Code Injection Through an Attacker-Controlled Portfolio Path<![CDATA[ ## Vulnerability Details **File Location**: `scripts/script.sh`, lines 5–7 and 64–69 **Vulnerability Type**: Python source injection through an unquoted heredoc **Risk Level**: High ### Vulnerable Code ```bash DATA_DIR="${FUND_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/fund-invest-advisor}" PORTFOLIO="$DATA_DIR/portfolio.jsonl" mkdir -p "$DATA_DIR" ``` ```bash cmd_holdings() { [ ! -f "$PORTFOLIO" ] && { echo "No holdings. Use: fund-invest-advisor add <fund> <amount>"; return; } python3 << PYEOF import json holdings = {} with open('$PORTFOLIO') as f: ``` ### Technical Analysis The `FUND_DIR` environment variable influences `PORTFOLIO`. The resulting path is interpolated directly into an unquoted heredoc that is interpreted as Python source code. Although the path appears inside a single-quoted Python string, Bash performs parameter expansion before Python receives the heredoc. A path containing a single quote and additional Python syntax can terminate the string literal and inject arbitrary statements or expressions. Shell quoting of `"$PORTFOLIO"` elsewhere does not protect this operation because the vulnerability occurs when Bash constructs the embedded Python program. The same vulnerable `cmd_holdings` implementation is also reached through the `pnl` command. ### Attack Path 1. An attacker causes the victim to run the script with an attacker-controlled `FUND_DIR` value. 2. The attacker chooses a value containing Python string delimiters and executable Python syntax. 3. The script creates or uses the resulting directory and derives `PORTFOLIO` from it. 4. The victim invokes: - `scripts/script.sh holdings`, or - `scripts/script.sh pnl`. 5. Bash expands `$PORTFOLIO` into the unquoted Python heredoc. 6. The injected path terminates the intended Python string and introduces attacker-controlled Python code. 7. Python executes that code with the privileges and environment of the user running the script. ### Impact Assessment Succes ...[truncated 462 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Do not interpolate filesystem paths or other variable data into generated Python source. Pass the path as a positional argument and quote the heredoc delimiter: ```bash cmd_holdings() { if [[ ! -f "$PORTFOLIO" ]]; then echo "No holdings. Use: fund-invest-advisor add <fund> <amount>" return fi python3 - "$PORTFOLIO" <<'PYEOF' import json import sys portfolio_path = sys.argv[1] holdings = {} with open(portfolio_path, encoding="utf-8") as f: for line in f: d = json.loads(line) fund = d["fund"] amount = float(d["amount"]) if d["action"] == "buy": holdings[fund] = holdings.get(fund, 0) + amount else: holdings[fund] = holdings.get(fund, 0) - amount PYEOF } ``` Additional hardening should include: - Use quoted heredoc delimiters whenever the embedded source must remain literal. - Validate that `FUND_DIR` resolves to an expected user-owned location. - Reject unsafe directory types, including symbolic links where inappropriate. - Create the data directory with restrictive permissions, such as `umask 077` and `mkdir -p -- "$DATA_DIR"`. - Add regression tests using paths containing quotes, backslashes, spaces, newlines, and Python metacharacters. ]]>
