Back to skill

Security audit

free-feishu-voice

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it claims, but its voice-message scripts include unsafe runtime package installation, weak credential-file handling, and an input-handling flaw that can execute arbitrary local code.

Review before installing. Use this only with non-sensitive message content, create the Feishu config file with private permissions, avoid the Edge TTS script until the heredoc injection flaw is fixed, and install dependencies explicitly in an isolated environment with pinned versions instead of letting the script run pip automatically.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (4)

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. ]]>

T08 · Insecure Dependencies

Error
Location
SKILL.md:179
Finding
Unpinned Third-Party Package Is Installed Automatically at Runtime<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 179-182; the same unpinned command is also documented at line 340 **Vulnerability Type**: Unsafe runtime dependency installation **Risk Level**: High ### Vulnerable Code ```bash # 检查edge_tts是否安装 if ! python3 -c "import edge_tts" &> /dev/null; then echo "📦 安装edge_tts依赖..." pip3 install edge-tts --quiet fi ``` The installation instructions repeat the unpinned operation: ```bash pip3 install edge-tts ``` ### Technical Analysis The enhanced script automatically invokes `pip3` when `edge_tts` is unavailable. It does not specify an audited version, verify package hashes, use a lock file, or explicitly constrain the package index. Python package installation can execute package build and installation logic. Therefore, the effective code run by the skill can change without any modification to `SKILL.md`. Security depends on the current package-index response, local `pip` configuration, configured mirrors, DNS/TLS trust, and the integrity of future package releases. This finding does not establish that the named package is malicious. The vulnerability is that an unreviewed and mutable dependency is fetched and installed automatically during normal execution. ### Attack Path 1. The target environment does not already contain an importable `edge_tts` package. 2. A user invokes the enhanced voice script. 3. The dependency check fails, causing an automatic `pip3 install edge-tts --quiet`. 4. A compromised release, compromised package index, malicious configured mirror, or attacker-controlled `pip` configuration supplies unsafe package content. 5. Package installation or subsequent import executes the supplied code with the invoking user's permissions. ### Impact Assessment A compromised dependency can obtain arbitrary code execution as the user running the script. This may expose: - Feishu application credentials and access tokens. - Message text submitted for speech generation. - Files ...[truncated 373 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove automatic package installation from the operational script. Dependency installation should be an explicit, separately approved setup action. 2. Pin the package to a reviewed version. 3. Use a hash-locked requirements file, for example: ```text edge-tts==<reviewed-version> \ --hash=sha256:<verified-distribution-hash> ``` 4. Install with hash enforcement: ```bash python3 -m pip install --require-hashes -r requirements.txt ``` 5. Use an isolated virtual environment rather than modifying the user or system Python environment. 6. Explicitly use an approved package index and ensure unexpected local `pip` configuration cannot redirect downloads. 7. Scan and periodically review pinned dependencies before deliberately updating them. 8. Do not recommend running package installation as root. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:84
Finding
Predictable Shared Temporary Files Permit Symlink and Race Attacks<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 84-92 and 118 **Vulnerability Type**: Unsafe predictable temporary-file handling **Risk Level**: Medium ### Vulnerable Code ```bash # 生成语音 echo "🎙️ 生成语音文件..." echo "$TEXT" | espeak-ng -v zh --stdout > /tmp/voice.wav 2>/dev/null ffmpeg -i /tmp/voice.wav -acodec libopus -ac 1 -ar 16000 /tmp/voice.opus -y 2>/dev/null # 上传文件 echo "📤 上传语音文件..." UPLOAD_RESPONSE=$(curl -s -X POST "https://open.feishu.cn/open-apis/im/v1/files" \ -H "Authorization: Bearer $TOKEN" \ -F "file_type=opus" \ -F "file=@/tmp/voice.opus") ``` Cleanup also uses the same globally predictable paths: ```bash rm -f /tmp/voice.wav /tmp/voice.opus 2>/dev/null ``` ### Technical Analysis The basic script stores audio at fixed names under the shared `/tmp` directory. It does not securely create the files, establish a private directory, validate file ownership, reject symbolic links, or atomically preserve the relationship between generated and uploaded files. Shell redirection follows symbolic links. FFmpeg is also instructed to overwrite the predictable output path using `-y`. Another local process can pre-create or replace these paths, potentially redirecting writes to another file writable by the victim. There is also a time-of-check/time-of-use opportunity between generation and upload: a local attacker may replace `/tmp/voice.opus` after FFmpeg produces it but before `curl` opens it. Concurrent executions also use the same paths and can overwrite or upload each other's audio. ### Attack Path Possible local symlink attack: 1. A local attacker predicts that the victim will run the script. 2. The attacker creates `/tmp/voice.wav` or `/tmp/voice.opus` as a symbolic link to a file that the victim can write. 3. The victim invokes the script. 4. Shell redirection or FFmpeg follows the link and overwrites the target using the victim's permissions. Possible upload race: 1. The script creates `/tmp/voice.opus`. 2. Bef ...[truncated 1021 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Create a private, uniquely named temporary directory and clean it through an exit trap: ```bash TMP_DIR=$(mktemp -d) chmod 700 "$TMP_DIR" trap 'rm -rf -- "$TMP_DIR"' EXIT WAV_FILE="$TMP_DIR/voice.wav" OPUS_FILE="$TMP_DIR/voice.opus" espeak-ng -v zh --stdout <<<"$TEXT" >"$WAV_FILE" ffmpeg -i "$WAV_FILE" -acodec libopus -ac 1 -ar 16000 "$OPUS_FILE" -y UPLOAD_RESPONSE=$(curl ... -F "file=@$OPUS_FILE") ``` Additionally: 1. Set a restrictive `umask`, such as `umask 077`, before creating temporary files. 2. Never use fixed names directly under a shared temporary directory. 3. Use an `EXIT`, `INT`, and `TERM` cleanup strategy so files are removed on both success and failure. 4. Avoid running the script with elevated privileges. 5. If high-integrity upload semantics are required, open and retain a stable file descriptor or otherwise ensure that the uploaded object cannot be replaced between generation and upload. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:31
Finding
Credential Configuration File Is Created Without Enforced Restrictive Permissions<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 31-44; equivalent logic appears at lines 141-155 **Vulnerability Type**: Insecure sensitive configuration-file permissions **Risk Level**: Medium ### Vulnerable Code ```bash else # 配置文件不存在时生成模板 echo "⚠️ 配置文件不存在,生成模板到 $CONFIG_FILE" mkdir -p "$(dirname "$CONFIG_FILE")" cat > "$CONFIG_FILE" << 'EOF' { "feishu_app_id": "your_app_id_here", "feishu_app_secret": "your_app_secret_here", "feishu_chat_id": "your_chat_id_here", "default_text": "默认消息" } EOF echo "❌ 请先编辑 $CONFIG_FILE 填写正确的配置后重试" exit 1 fi ``` ### Technical Analysis The generated file is intended to hold `feishu_app_secret`, but the script does not set a restrictive `umask` or explicitly apply mode `0600`. It similarly does not ensure that the parent configuration directory is accessible only to its owner. File permissions therefore depend on the caller's existing `umask`. With a common permissive setting such as `022`, a newly created regular file can receive mode `0644`, making it readable by other local users. Although the initial template contains placeholders, the instructions tell the user to edit this same file and insert real credentials. The insecure mode remains unless the user changes it manually. An environment-controlled `FEISHU_VOICE_CONFIG` path also means the file may be created outside the expected private configuration directory. ### Attack Path 1. The user runs the script without an existing configuration file and with a permissive `umask`. 2. The script creates the template with permissions that allow other local users to read it. 3. The user edits that same file and inserts the real Feishu application secret. 4. Another local account reads the configuration file. 5. The attacker uses the recovered application credentials to request a tenant access token and perform actions allowed to that Feishu application. ### Impact Assessment Exposure of the application secret may allow unauthorized a ...[truncated 574 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Enforce private permissions before creating the directory or file: ```bash umask 077 CONFIG_DIR=$(dirname -- "$CONFIG_FILE") mkdir -p -- "$CONFIG_DIR" chmod 700 -- "$CONFIG_DIR" if [ ! -e "$CONFIG_FILE" ]; then install -m 600 /dev/null "$CONFIG_FILE" cat >"$CONFIG_FILE" <<'EOF' { "feishu_app_id": "your_app_id_here", "feishu_app_secret": "your_app_secret_here", "feishu_chat_id": "your_chat_id_here", "default_text": "默认消息" } EOF fi chmod 600 -- "$CONFIG_FILE" ``` Further hardening should include: 1. Validate that the configuration path is a regular file and not a symbolic link. 2. Verify that the file is owned by the current user before reading secrets from it. 3. Reject configuration files writable by group or other users. 4. Restrict or validate paths supplied through `FEISHU_VOICE_CONFIG`. 5. Prefer an operating-system credential store or dedicated secret manager over a plaintext JSON file. 6. Document secret rotation procedures in case the file has previously been broadly readable. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (12)

Tool Parameter Abuse

High
Category
Tool Misuse
Content
fi

# 清理临时文件
rm -f /tmp/voice.wav /tmp/voice.opus 2>/dev/null
echo "🧹 清理临时文件完成"
```
Confidence
85% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Chaining Abuse

High
Category
Tool Misuse
Content
### 6. 依赖安装
```bash
# Debian/Ubuntu
sudo apt update && sudo apt install -y jq ffmpeg python3 python3-pip

# CentOS/RHEL
sudo yum install -y jq ffmpeg python3 python3-pip
Confidence
75% confidence
Finding
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

External Transmission

Medium
Category
Data Exfiltration
Content
# ===================== 核心逻辑 =====================
# 获取令牌
echo "🔑 获取飞书访问令牌..."
TOKEN=$(curl -s -X POST "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal" \
  -H "Content-Type: application/json" \
  -d "{\"app_id\":\"$APP_ID\",\"app_secret\":\"$APP_SECRET\"}" \
  | jq -r '.tenant_access_token // empty')
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
# ===================== 核心逻辑 =====================
# 获取令牌
echo "🔑 获取飞书访问令牌..."
TOKEN=$(curl -s -X POST "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal" \
  -H "Content-Type: application/json" \
  -d "{\"app_id\":\"$APP_ID\",\"app_secret\":\"$APP_SECRET\"}" \
  | jq -r '.tenant_access_token // empty')
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
# 发送消息
echo "📨 发送语音消息..."
SEND_RESPONSE=$(curl -s -X POST "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"receive_id\":\"$CHAT_ID\",\"msg_type\":\"audio\",\"content\":\"{\\\"file_key\\\":\\\"$FILE_KEY\\\"}\"}")
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
# 发送消息
echo "📨 发送语音消息..."
SEND_RESPONSE=$(curl -s -X POST "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"receive_id\":\"$CHAT_ID\",\"msg_type\":\"audio\",\"content\":\"{\\\"file_key\\\":\\\"$FILE_KEY\\\"}\"}")
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill omits a clear privacy disclosure even though it sends user-supplied text and generated audio to Feishu, and the Edge TTS variant also sends text to an external TTS provider. Users may unknowingly transmit sensitive or regulated content to third parties, creating privacy, compliance, and data-handling risks.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The optimization table states that any failure scenario ensures temporary files are cleaned. In the basic send_voice.sh flow, failures after generating /tmp/voice.wav and /tmp/voice.opus but before the final cleanup—such as upload failure at L95-L98 or send failure at L111-L114—exit without deleting those files, so the documentation materially overstates the script's behavior.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
### 6. 依赖安装
```bash
# Debian/Ubuntu
sudo apt update && sudo apt install -y jq ffmpeg python3 python3-pip

# CentOS/RHEL
sudo yum install -y jq ffmpeg python3 python3-pip
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
sudo apt update && sudo apt install -y jq ffmpeg python3 python3-pip

# CentOS/RHEL
sudo yum install -y jq ffmpeg python3 python3-pip

# macOS
brew install jq ffmpeg python3
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Natural-Language Policy Violations

Low
Confidence
90% confidence
Finding
The file sets `default_voice` to `zh-CN-XiaoxiaoNeural`, uses Chinese default text, and all examples are oriented around Chinese speech output. Because no language choice or explicit justification for a China-specific locale constraint is documented, this appears to impose a locale preference without user opt-in.

Intent-Code Divergence

Low
Confidence
92% confidence
Finding
The documentation describes dependency handling as checking for dependencies and prompting the user to install them. However, send_voice_edge.sh goes further by automatically running 'pip3 install edge-tts --quiet' at L179-L181, which is a side effect not reflected by the stated behavior and changes the host environment.

Static analysis

No suspicious patterns detected.