T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/speak_to_baobao.py:60- Finding
Undisclosed Feishu Upload and Message Delivery Using Ambient Credentials
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is mainly a MiMo text-to-speech helper, but bundled scripts can upload generated audio to Feishu and send it using existing credentials without top-level disclosure.
Review this before installing. Use the local-only speak.sh path only for non-sensitive text unless you are comfortable sending text to MiMo. Do not run speak_to_baobao.py or gen_all_voices.py unless you intentionally want generated audio uploaded and sent through Feishu, have verified the recipient, and understand which lark-cli account is authenticated.
scripts/speak_to_baobao.py:60Undisclosed Feishu Upload and Message Delivery Using Ambient Credentials
scripts/speak_to_baobao.py:43Predictable Temporary Paths Allow File Collisions and Symlink-Based Write Redirection
scripts/mimo_speak.py:50MiMo API Key Is Passed Through Observable Process Arguments
scripts/speak.sh:32Unescaped User Input Permits JSON Payload Injection in the Bash Client
The code does use MiMo TTS, so it is related to speech synthesis. However, its primary behavior is not a general-purpose skill that reads arbitrary user text aloud. Instead, it batch-generates sample clips for a hardcoded list of voices, saves and converts the audio locally, then uploads and sends those files through Feishu. Those messaging and file-upload behaviors are undeclared, and the script’s purpose is closer to internal voice-sample generation/distribution than an end-user TTS skill.
The declared description says this is a MiMo text-to-speech skill, which is only part of what the code does. The primary code path is not merely synthesizing speech for local return/playback; it additionally packages and delivers the generated audio through Feishu messaging. That outbound messaging/integration behavior is a substantive undeclared capability and resource access mismatch relative to the description and empty permissions. Temporary file creation and ffmpeg conversion are supporting details, but the Feishu upload/send behavior materially changes the skill’s effective purpose from simple TTS to TTS-plus-message-delivery.
Data flows directly from a source (env vars, files, network) to a sink (network output, exec, file write) without intermediate validation.
if upload_data.get("ok"):
file_key = upload_data["data"]["file_key"]
content = json.dumps({"file_key": file_key})
send = subprocess.run(
["lark-cli", "im", "+messages-send",
"--user-id", os.environ.get("FEISHU_USER_OPEN_ID", ""),
"--msg-type", "audio",
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.
EOF)
# 调用 MiMo TTS API (通过 chat completions 接口)
RESPONSE=$(curl -s -X POST 'https://api.xiaomimimo.com/v1/chat/completions' \
-H "api-key: $API_KEY" \
-H 'Content-Type: application/json' \
-d "$PAYLOAD")
The skill description presents this as a TTS fallback, but the code uploads and sends synthesized audio via Feishu, adding an undeclared communication capability. This scope mismatch is security-relevant because it can surprise users and reviewers, conceal exfiltration paths, and bypass least-privilege expectations for a narrowly described skill.
Data flows directly from a source (env vars, files, network) to a sink (network output, exec, file write) without intermediate validation.
file_key = upl_data.get("data", {}).get("file_key", "")
if file_key:
send = subprocess.run(
["lark-cli", "im", "+messages-send",
"--user-id", os.environ.get("FEISHU_USER_OPEN_ID", ""),
"--msg-type", "audio",
The skill declares executable capabilities involving environment variables and shell-style commands but does not declare any corresponding tool scope or permissions boundary. This creates an authorization and review gap: a caller or platform may treat the skill as documentation-only while it actually relies on command execution and secret access.
The trigger description is broad and includes common conversational phrases like read aloud, TTS, and convert text to voice, which can cause accidental invocation. In this context, accidental triggering matters because the skill sends user-provided text to an external third-party API, potentially disclosing content the user did not intend to export.
The skill transmits user-provided text and an API bearer token to an external service over the network. While outbound transmission is expected for a cloud TTS skill, it is still security-relevant because sensitive user content may be exfiltrated to a third party if invoked on private text or without clear consent.
curl -X POST 'https://api.xiaomimimo.com/v1/audio/speech' \
-H "Authorization: Bearer $MIMO_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
The skill transmits user-provided text and an API bearer token to an external service over the network. While outbound transmission is expected for a cloud TTS skill, it is still security-relevant because sensitive user content may be exfiltrated to a third party if invoked on private text or without clear consent.
curl -X POST 'https://api.xiaomimimo.com/v1/audio/speech' \
-H "Authorization: Bearer $MIMO_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
The docstring and generated content are written as fixed Chinese-language instructions and sample speech, and the script does not offer any language or locale opt-in. This appears to enforce a specific language behavior in natural-language content without documenting that the skill is intentionally limited to a Chinese-only context.
The script consumes sensitive environment variables and transmits data to external services automatically, but does not present any warning, consent step, or clear disclosure. In a skill advertised as TTS-focused, this makes external data flow less expected and therefore more security-significant.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
}, ensure_ascii=False)
# curl 请求
proc = subprocess.run(
["curl", "-s", "-X", "POST", "https://api.xiaomimimo.com/v1/chat/completions",
"-H", f"api-key: {API_KEY}",
"-H", "Content-Type: application/json",
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
}, ensure_ascii=False)
# curl 请求
proc = subprocess.run(
["curl", "-s", "-X", "POST", "https://api.xiaomimimo.com/v1/chat/completions",
"-H", f"api-key: {API_KEY}",
"-H", "Content-Type: application/json",
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
}, ensure_ascii=False)
# curl 请求
proc = subprocess.run(
["curl", "-s", "-X", "POST", "https://api.xiaomimimo.com/v1/chat/completions",
"-H", f"api-key: {API_KEY}",
"-H", "Content-Type: application/json",
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# curl 请求
proc = subprocess.run(
["curl", "-s", "-X", "POST", "https://api.xiaomimimo.com/v1/chat/completions",
"-H", f"api-key: {API_KEY}",
"-H", "Content-Type: application/json",
"-d", payload],
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# curl 请求
proc = subprocess.run(
["curl", "-s", "-X", "POST", "https://api.xiaomimimo.com/v1/chat/completions",
"-H", f"api-key: {API_KEY}",
"-H", "Content-Type: application/json",
"-d", payload],
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
f.write(audio_bytes)
ogg_path = f"{DIR}/{voice}.ogg"
subprocess.run(["ffmpeg", "-y", "-i", wav_path, "-c:a", "libopus", "-b:a", "64k", "-ar", "48000", ogg_path],
capture_output=True)
# 上传到飞书
The script does more than synthesize speech: it uploads generated audio to Feishu and sends it to a recipient automatically. In a TTS skill, hidden outbound delivery expands the trust boundary and can leak user content or generated artifacts to an external messaging platform without clear user awareness or consent.
Adding external file-upload and messaging capability is unrelated to the core TTS function and creates an unnecessary exfiltration channel. If the script is reused with user-provided text, synthesized audio containing sensitive content could be transmitted to third-party infrastructure unexpectedly.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
capture_output=True)
# 上传到飞书
upload = subprocess.run(
["lark-cli", "api", "POST", "/open-apis/im/v1/files",
"--file", f"file={ogg_path}",
"--data", json.dumps({"file_type": "opus", "file_name": f"{voice}.ogg"})],
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
if upload_data.get("ok"):
file_key = upload_data["data"]["file_key"]
content = json.dumps({"file_key": file_key})
send = subprocess.run(
["lark-cli", "im", "+messages-send",
"--user-id", os.environ.get("FEISHU_USER_OPEN_ID", ""),
"--msg-type", "audio",
The top-level documentation says "语音合成并发送到飞书" (synthesize speech and send to Feishu), which implies an outbound delivery step. In reality, the code only calls the MiMo API, decodes audio, writes a WAV file locally, and prints its path; there is no Feishu integration.
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
print(json.dumps({"status": "synthesizing", "text": TEXT, "voice": VOICE}))
try:
proc = subprocess.run(
["curl", "-s", "-X", "POST", "https://api.xiaomimimo.com/v1/chat/completions",
"-H", f"api-key: {API_KEY}",
"-H", "Content-Type: application/json",
The script sends arbitrary user-provided text to an external third-party TTS API, which is a real data egress risk if the skill is used on sensitive content. In this skill context, external transmission is expected for cloud TTS, but it is still security-relevant because users may assume local synthesis or may unknowingly submit confidential data.
try:
proc = subprocess.run(
["curl", "-s", "-X", "POST", "https://api.xiaomimimo.com/v1/chat/completions",
"-H", f"api-key: {API_KEY}",
"-H", "Content-Type: application/json",
"-d", payload],
No suspicious patterns detected.