T09 · Insecure Skill Coding Practices
Error
- Location
- hue.sh:37
- Finding
- Arbitrary Python Code Execution Through Unvalidated Hexadecimal Color Input<![CDATA[ ## Vulnerability Details **File Location**: `hue.sh`, lines 37–48 and 85–98 **Vulnerability Type**: Python source-code injection **Risk Level**: High ### Vulnerable Code ```sh hex_to_hsb() { hex=$(echo "$1" | sed 's/#//') python3 - <<EOF import colorsys hex_color = "$hex" r, g, b = tuple(int(hex_color[i:i+2], 16) / 255.0 for i in (0, 2, 4)) h, s, v = colorsys.rgb_to_hsv(r, g, b) # Hue is 0-65535, Sat is 0-254, Bri is 0-254 print(f"\"on\":true,\"hue\":{int(h * 65535)},\"sat\":{int(s * 254)},\"bri\":{int(v * 254)}") EOF } ``` The attacker-controlled value reaches this function through the following code: ```sh case "$1" in red) HEX="#FF0000" ;; blue) HEX="#0000FF" ;; green) HEX="#00FF00" ;; yellow) HEX="#FFFF00" ;; orange) HEX="#FFA500" ;; pink) HEX="#FFC0CB" ;; purple) HEX="#800080" ;; white) HEX="#FFFFFF" ;; # Use hex for white and colors, but keep specialized CT for warm/cold warm) HSB="\"on\":true,\"sat\":0,\"bri\":254,\"ct\":450" ;; cold) HSB="\"on\":true,\"sat\":0,\"bri\":254,\"ct\":153" ;; \#*) HEX="$1" ;; *) echo "Unknown color: $1" ; exit 1 ;; esac if [ -n "$HEX" ]; then HSB=$(hex_to_hsb "$HEX") unset HEX fi ``` ### Technical Analysis Every color argument beginning with `#` is accepted by the `\#*` shell pattern. The code does not verify that the remainder is exactly six hexadecimal characters. After removing the first `#`, the value is interpolated directly into a Python heredoc: ```python hex_color = "$hex" ``` Because the value is inserted into Python source code rather than passed as data, an input containing quotation marks, statement separators, and a Python comment can terminate the string and introduce additional executable Python statements. The generated source is then execu ...[truncated 1623 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Strictly validate hexadecimal colors before processing them. Accept only exactly six hexadecimal digits following `#`: ```sh case "$1" in \#[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]) HEX="$1" ;; *) echo "Invalid hexadecimal color" >&2 exit 1 ;; esac ``` 2. Never interpolate external values into Python source code. Pass the color as an argument: ```sh hex_to_hsb() { python3 - "${1#\#}" <<'PY' import colorsys import re import sys hex_color = sys.argv[1] if not re.fullmatch(r"[0-9A-Fa-f]{6}", hex_color): raise SystemExit("Invalid hexadecimal color") r, g, b = ( int(hex_color[i:i + 2], 16) / 255.0 for i in (0, 2, 4) ) h, s, v = colorsys.rgb_to_hsv(r, g, b) print( f'"on":true,"hue":{int(h * 65535)},' f'"sat":{int(s * 254)},"bri":{int(v * 254)}' ) PY } ``` 3. Use a quoted heredoc delimiter such as `<<'PY'` to disable shell expansion within the Python source. 4. Retain validation in both the shell caller and Python implementation as defense in depth. 5. Add negative tests for quotation marks, whitespace, newlines, command syntax, incorrect lengths, and non-hexadecimal characters. ]]>
