T09 · Insecure Skill Coding Practices
- Location
scripts/stats.sh:82- Finding
Python Code Injection Through a User-Controlled Data Directory
- Content
View full analysis
Vulnerability Details
File Location:
scripts/stats.sh, lines 82–94
Vulnerability Type: Python source-code injection
Risk Level: HighVulnerable Code
bash CHECKPOINT="$DATA_DIR/.checkpoint.json" if [[ -f "$CHECKPOINT" ]]; then echo "" echo "📍 체크포인트:" python3 -c " import json with open('$CHECKPOINT', encoding='utf-8') as f: cp = json.load(f) for k, v in cp.items(): print(f' {k}: {v}') " fiDATA_DIRis initialized from the first command-line argument earlier in the script:bash DATA_DIR="${1:-./data}"Technical Analysis
The user-controlled
DATA_DIRvalue is used to constructCHECKPOINT, which is then interpolated directly into Python source passed topython3 -c.Shell quoting does not make this safe at the Python-language layer. A checkpoint path containing a single quote, line break, or other Python syntax can terminate the string literal in
with open('$CHECKPOINT', ...)and inject additional Python statements.The
[[ -f "$CHECKPOINT" ]]check does not sanitize the path. An attacker who controls the argument and can prepare a matching crafted filesystem path can satisfy that check before the vulnerable Python command is evaluated.Attack Path
- An attacker chooses a malicious data-directory name containing characters that terminate the single-quoted Python path literal and introduce attacker-controlled Python statements.
- The attacker creates the crafted directory structure and a corresponding
.checkpoint.jsonpath so that[[ -f "$CHECKPOINT" ]]succeeds. - The victim or an automated process invokes:
bash bash scripts/stats.sh "$ATTACKER_CONTROLLED_DIRECTORY" - The shell expands
$CHECKPOINTinto the source-code string supplied topython3 -c. - Python parses the injected content as executable source rather than as path data.
- The injected Python statements execute with the privilege ...[truncated 715 chars]
- Remediation
View remediation
Remediation Suggestions
Do not embed filesystem paths or other external values into source code. Pass the checkpoint path as a positional argument and read it from
sys.argv:bash CHECKPOINT="$DATA_DIR/.checkpoint.json" if [[ -f "$CHECKPOINT" ]]; then echo "" echo "Checkpoint:" python3 - "$CHECKPOINT" <<'PYEOF' import json import sys checkpoint = sys.argv[1] with open(checkpoint, encoding="utf-8") as f: cp = json.load(f) for key, value in cp.items(): print(f" {key}: {value}") PYEOF fiThis keeps the path as data throughout execution and prevents it from changing the Python program's syntax.
Additional hardening should include:
- Preserve the quoted shell argument
"$CHECKPOINT". - Avoid constructing interpreter programs with shell-expanded input.
- Reject unexpected file types and consider resolving the path before use if the caller should be restricted to a designated data root.
- Run the script with the minimum required filesystem permissions.
- Add a regression test using directory names containing single quotes, spaces, newlines, and Python metacharacters.
- Preserve the quoted shell argument
