T09 · Insecure Skill Coding Practices
- Location
scripts/notify-linux.sh:11- Finding
Python Code Injection Through Unvalidated Script Arguments in Linux Notification Script
- Content
View full analysis
/dev/null; then CUSTOM_SOUND=$(jq -r ".sounds.${TYPE} // empty" "$CONFIG_PATH" 2>/dev/null) elif command -v python3 &>/dev/null; then CUSTOM_SOUND=$(python3 -c "import json; c=json.load(open('$CONFIG_PATH')); print(c.get('sounds',{}).get('$TYPE',''))" 2>/dev/null) fi fi ``` ### Technical Analysis The script accepts `TYPE` and `CONFIG_PATH` as command-line arguments and directly interpolates both values into Python source passed to `python3 -c`. Shell quoting does not make this safe because the interpolated data is inserted inside Python string literals. An attacker can include quotes, parentheses, semicolons, and Python expressions in either argument to terminate the intended expression and append arbitrary Python statements. The vulnerable branch is reached when: 1. The supplied configuration path references an existing file. 2. `jq` is unavailable. 3. `python3` is available. The configured hooks normally pass fixed notification types, but the script is also documented for standalone invocation and does not enforce an allowlist for `TYPE`. ### Attack Path 1. The attacker causes the script to be invoked with an existing JSON configuration file. 2. The environment does not have `jq`, causing the Python fallback to run. 3. The attacker supplies a crafted `TYPE`, for example: ```bash bash scripts/notify-linux.sh \ "x','')); __import__('os').system('touch /tmp/agent-notify-pwned'); #" \ ./config/default.json ``` 4. The generated Python program is equivalent to an expression containing: ```python __import__('os').system('touch /tmp/agent-notify-pwned') ``` 5. Python executes the injected operating- ...[truncated 836 chars]- Remediation
View remediation
/dev/null ) ``` Additionally: 1. Restrict `TYPE` to the supported values before processing it: ```bash case "$TYPE" in confirm|done|error|default) ;; *) echo "Unsupported notification type" >&2; exit 2 ;; esac ``` 2. Resolve and validate the configuration path if callers are not intended to select arbitrary files. 3. Fail safely when JSON parsing fails rather than continuing with partially initialized data. 4. Add regression tests containing quotes, semicolons, command substitutions, newlines, and Python syntax in both arguments. ]]>
