T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/shellguard-scanner.sh:340
- Finding
- Arbitrary Python Code Execution Through Crafted Scanned Filenames<![CDATA[ ## Vulnerability Details **File Location**: `scripts/shellguard-scanner.sh:340-375` **Vulnerability Type**: Python source injection through untrusted filename interpolation **Risk Level**: High ### Vulnerable Code ```bash # Unicode zero-width characters (requires python3 check) if command -v python3 &>/dev/null; then local zwc_count zwc_count=$(python3 -c " import sys, unicodedata text = open('$file', 'r', errors='replace').read() zwc = [c for c in text if unicodedata.category(c) == 'Cf' or ord(c) in (0x200B,0x200C,0x200D,0xFEFF,0x00AD,0x2060,0x180E)] print(len(zwc)) " 2>/dev/null || echo "0") if (( zwc_count > 0 )); then add_finding "TIER3-OBFUSCATION" "$fname — CRITICAL: $zwc_count zero-width/invisible characters (steganography)" score_add SCORE_OBFUSCATION 15 20 fi fi # Bidirectional control characters if python3 -c " import sys text = open('$file', 'r', errors='replace').read() bidi = [c for c in text if ord(c) in (0x202E,0x202D,0x202A,0x202B,0x2066,0x2067,0x2068,0x202C,0x2069)] sys.exit(0 if bidi else 1) " 2>/dev/null; then add_finding "TIER3-OBFUSCATION" "$fname — CRITICAL: Bidirectional override characters (text spoofing attack)" score_add SCORE_OBFUSCATION 18 20 fi # Unicode tag range (U+E0000..E007F) — invisible instruction injection if python3 -c " import sys text = open('$file', 'r', errors='replace').read() tags = [c for c in text if 0xE0000 <= ord(c) <= 0xE007F] sys.exit(0 if tags else 1) " 2>/dev/null; then add_finding "TIER3-OBFUSCATION" "$fname — CRITICAL: Unicode tag characters (U+E0000 range) — invisible content injection" score_add SCORE_OBFUSCATION 20 20 fi ``` ### Technical Analysis The scanner embeds the value of `$file` directly inside Python source passed to `python3 -c`. Although the shell expands `$file` inside a double-quoted shell string, the resulting value is placed between single quotes in this Python statement: ```python text = open('$file', 'r', errors='repla ...[truncated 2330 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Never interpolate a filename into generated Python source. Pass it as a separate argument and retrieve it through `sys.argv`. Use a fixed, quoted heredoc for each check: ```bash zwc_count=$(python3 - "$file" <<'PY' import sys import unicodedata with open(sys.argv[1], "r", errors="replace") as stream: text = stream.read() zwc = [ char for char in text if unicodedata.category(char) == "Cf" or ord(char) in (0x200B, 0x200C, 0x200D, 0xFEFF, 0x00AD, 0x2060, 0x180E) ] print(len(zwc)) PY ) ``` Apply the same argument-passing design to the bidirectional-control and Unicode-tag checks. Additional hardening should include: 1. Consolidate all three Unicode checks into one fixed Python script or one quoted heredoc invocation. 2. Treat paths as opaque data and never embed them into shell, Python, regular-expression, or JSON source text. 3. Add regression tests using filenames containing single quotes, double quotes, backslashes, newlines, spaces, shell metacharacters, and non-ASCII characters. 4. Run scans of hostile packages in a sandbox with no credentials, restricted filesystem access, and disabled network access. 5. Ensure a malformed filename causes a controlled scan error rather than silently returning a clean result. ]]>
