T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:215
- Finding
- Arbitrary Python Code Execution Through Unquoted Heredoc Expansion<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 215-242 **Vulnerability Type**: Shell-to-Python source-code injection **Risk Level**: Critical ### Vulnerable Code ```bash OPUS_FILE=$(python3 << EOF import asyncio import edge_tts import subprocess import tempfile import os async def generate_voice(): # 生成MP3临时文件 with tempfile.NamedTemporaryFile(suffix='.mp3', delete=False) as mp3_file: communicate = edge_tts.Communicate("""$TEXT""", """$VOICE""") await communicate.save(mp3_file.name) # 转换为OPUS格式 opus_file = mp3_file.name.replace('.mp3', '.opus') cmd = [ 'ffmpeg', '-i', mp3_file.name, '-acodec', 'libopus', '-ac', '1', '-ar', '16000', opus_file, '-y' ] subprocess.run(cmd, capture_output=True, check=True) return opus_file # 兼容Windows系统 import sys if sys.platform == "win32": asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy()) opus_path = asyncio.run(generate_voice()) print(opus_path) EOF ) ``` ### Technical Analysis The heredoc delimiter is not quoted. Consequently, the shell expands `$TEXT` and `$VOICE` before passing the heredoc body to Python. Both values can originate from positional script arguments: ```bash TEXT="${1:-$DEFAULT_TEXT}" VOICE="${2:-$DEFAULT_VOICE}" ``` The expanded values are inserted directly into triple-quoted Python string literals. Triple quotes do not safely encode untrusted data when the data itself is being used to construct Python source code. An input containing a terminating triple-quote sequence can escape the intended string literal and insert additional Python statements. Shell quoting at the script invocation boundary does not prevent this issue: once the argument has been assigned to `TEXT` or `VOICE`, heredoc expansion embeds its contents into the generated Python program. ### Attack Path 1. An attacker obtains influence over the message text or voice argume ...[truncated 1067 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Use a quoted heredoc so the shell cannot expand user-controlled values into Python source, and transfer values through environment variables or command-line arguments. For example: ```bash export FEISHU_TTS_TEXT="$TEXT" export FEISHU_TTS_VOICE="$VOICE" OPUS_FILE=$(python3 <<'PYTHON' import asyncio import edge_tts import os text = os.environ["FEISHU_TTS_TEXT"] voice = os.environ["FEISHU_TTS_VOICE"] async def generate_voice(): # Process text and voice strictly as data. ... PYTHON ) ``` Additional hardening should include: 1. Validate `VOICE` against an explicit allowlist of supported voice identifiers. 2. Apply reasonable length limits to message text. 3. Avoid generating source code from runtime input under all circumstances. 4. Remove exported variables immediately after use if environment exposure is a concern. 5. Run the TTS process as an unprivileged account with only the filesystem and network access required for the task. ]]>
