T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/stale_games.sh:27
- Finding
- Arbitrary Python Code Injection Through GOG_LIBRARY## Vulnerability Details **File Location**: `scripts/stale_games.sh`, lines 27–53 **Vulnerability Type**: Environment-variable injection into dynamically constructed Python source **Risk Level**: High ### Vulnerable Code ```bash # Extract stale installed games via python (jq may not be available) STALE_JSON=$(python3 -c " import json, sys from datetime import datetime, timezone with open('$GOG_LIBRARY') as f: lib = json.load(f) cutoff = datetime.fromisoformat('$CUTOFF').replace(tzinfo=None) stale = [] for g in lib.get('games', []): if not g.get('installed'): continue lp = g.get('last_played') if lp is None: stale.append(g) continue try: dt = datetime.fromisoformat(lp).replace(tzinfo=None) except Exception: stale.append(g) continue if dt < cutoff: stale.append(g) print(json.dumps(stale)) ") ``` ### Technical Analysis `GOG_LIBRARY` is supplied through an environment variable and inserted directly into a Python program passed to `python3 -c`. Shell quoting does not make this safe because the expansion occurs inside a double-quoted shell string, while the resulting value is placed inside a single-quoted Python string: ```python with open('$GOG_LIBRARY') as f: ``` A value containing a single quote, newline, and additional Python syntax can terminate the intended string and alter the generated program. Python then evaluates the injected statements with the privileges of the user running the Skill. This is source-code injection rather than shell command injection. Argument-array use elsewhere in the script does not mitigate this source-to-interpreter path. Exploitation requires the attacker to control or influence `GOG_LIBRARY`, such as through a wrapper, automation configuration, inherited environment, or unsafe scheduled-task configuration. ### Attack Path 1. An attacker gains influence ove ...[truncated 1189 chars]
- Remediation
- ## Remediation Suggestions Never interpolate file paths or other data into Python source. Pass values as positional arguments: ```bash STALE_JSON=$(python3 - "$GOG_LIBRARY" "$CUTOFF" <<'PY' import json import sys from datetime import datetime library_path = sys.argv[1] cutoff_text = sys.argv[2] with open(library_path, encoding="utf-8") as f: lib = json.load(f) cutoff = datetime.fromisoformat(cutoff_text).replace(tzinfo=None) # Continue processing here. PY ) ``` Additionally: - Verify that the path exists, is a regular file, and is readable before invoking Python. - Consider rejecting symbolic links if the automation is expected to read only a fixed configuration file. - Use a fixed script file or a single-quoted heredoc so shell expansion cannot modify Python source. - Run scheduled instances under the least-privileged user and with a controlled environment.
