Back to skill

Security audit

Xiaomi MiMo TTS

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a disclosed Xiaomi text-to-speech integration, but it needs Review because bundled scripts contain a local code-execution flaw and the docs recommend unpinned package execution.

Install only if you are comfortable sending the text you synthesize to Xiaomi's MiMo API using your API key. Avoid the documented unpinned `npx` and unnecessary `pip install openai` examples unless you pin and trust the exact versions. Do not pass untrusted text through the shell `--dry-run` path until the heredoc interpolation bug is fixed, and prefer constraining outputs to a dedicated audio directory.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/base/mimo-tts.sh:30
Finding
Arbitrary Python Code Execution Through Unsafe Heredoc Interpolation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/base/mimo-tts.sh:30-38` **Vulnerability Type**: Command injection through generated Python source **Risk Level**: High ### Vulnerable Code ```bash python3 - <<PY import json body={ 'model':'mimo-v2-tts', 'messages':[{'role':'user','content':'请朗读'},{'role':'assistant','content':"""$TEXT"""}], 'audio':{'format':'wav','voice':'$VOICE'} } print(json.dumps(body,ensure_ascii=False,indent=2)) PY ``` ### Technical Analysis The script places the user-controlled `TEXT` value and configurable `VOICE` value directly into Python source code contained in an unquoted heredoc. These values are not encoded as Python string literals before interpolation. An attacker can supply text containing a terminating triple quote followed by arbitrary Python statements. When the script is run with `--dry-run`, the generated source is passed to the local Python interpreter. The injected statements therefore execute as code rather than remaining TTS content. Shell argument quoting at the call site does not mitigate the vulnerability because the injection occurs when the script constructs a second programming-language context. ### Attack Path 1. An attacker supplies crafted TTS text containing a sequence that closes the Python triple-quoted string. 2. The attacker or an automation path invokes the base implementation in dry-run mode, for example: ```bash scripts/base/mimo-tts.sh '"""; import os; os.system("id"); x="""' output.ogg --dry-run ``` 3. The shell interpolates the crafted text into the heredoc. 4. Python parses the injected statements as part of the generated program. 5. The injected command executes with the operating-system privileges and environment inherited by the Skill process. Exploitation requires access to the dry-run path in `scripts/base/mimo-tts.sh`; normal callers that do not enable this option do not reach the vulnerable heredoc. ### Impact Assessment Successful exploitation prov ...[truncated 516 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Do not construct executable source code using interpolated user input. 1. Replace the generated Python program with static code. 2. Pass `TEXT` and `VOICE` through positional arguments, standard input, or environment variables. 3. Let `json.dumps` encode these values rather than attempting to place them inside Python string literals. 4. Alternatively, construct the preview with `jq --arg`, which safely JSON-encodes shell values. 5. Add regression tests containing triple quotes, backslashes, newlines, Unicode, and Python syntax. A safer implementation using environment variables is: ```bash TEXT="$TEXT" VOICE="$VOICE" python3 - <<'PY' import json import os body = { "model": "mimo-v2-tts", "messages": [ {"role": "user", "content": "请朗读"}, {"role": "assistant", "content": os.environ["TEXT"]}, ], "audio": { "format": "wav", "voice": os.environ["VOICE"], }, } print(json.dumps(body, ensure_ascii=False, indent=2)) PY ``` The quoted heredoc delimiter prevents shell expansion, while Python reads the input strictly as data. ]]>

T08 · Insecure Dependencies

Warning
Location
README.md:182
Finding
Unpinned Third-Party Package Installation and Execution Instructions<![CDATA[ ## Vulnerability Details **File Location**: `README.md:96-98` and `README.md:182-190` **Vulnerability Type**: Unsafe dependency acquisition and mutable package execution **Risk Level**: Medium ### Vulnerable Documentation ```bash pip install openai python3 ~/.openclaw/skills/mimo-tts/scripts/mimo_tts.py "你好" \ --voice default_zh --style "夹子音" --output output.wav ``` ```bash npx @openclaw/skill-runner run ~/.openclaw/skills/xiaomi-mimo-tts -- "<style>温柔</style>你好世界" output.ogg ``` ### Technical Analysis The README instructs users to install or execute registry packages without specifying an exact version or integrity constraint. The `npx` command may download the currently resolved package release and immediately execute its code. Consequently, the effective code executed by users can change after this Skill has been reviewed. A compromised publisher account, malicious upstream release, or package takeover could therefore turn the documented command into an arbitrary code-execution path. The unpinned `pip install openai` instruction has the same mutable-resolution concern. In addition, the reviewed Python implementation uses the standard library's `urllib.request` rather than the `openai` package, so this installation appears unnecessary for the bundled implementation and increases the dependency attack surface without supporting the declared runtime behavior. This finding concerns documented setup commands rather than code automatically executed during installation. Exploitation requires a user or automation system to follow the affected instructions. ### Attack Path 1. A user follows the README's `npx` or `pip install` instructions. 2. The package manager resolves an unspecified current version from its registry. 3. A malicious or compromised package release is downloaded. 4. For `npx`, downloaded package code is immediately executed; for `pip`, package installation hooks or later imports can execute package-controlled code. 5. The packa ...[truncated 782 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the `pip install openai` instruction unless the bundled implementation is changed to require that package. 2. Pin third-party tools to reviewed exact versions rather than allowing implicit latest-version resolution. 3. Use a lockfile and verified integrity hashes where supported. 4. Prefer locally installed, reviewed tooling over automatic download-and-execute behavior. 5. If `npx` remains documented, specify a reviewed version and advise users that it may download and execute third-party code. 6. In CI, install dependencies in a restricted environment with minimal credentials and filesystem access. For example: ```bash npx --yes @openclaw/skill-runner@<reviewed-exact-version> run \ ~/.openclaw/skills/xiaomi-mimo-tts -- \ "<style>温柔</style>你好世界" output.ogg ``` The placeholder must be replaced with a specifically reviewed release. Where possible, verify package integrity and publisher provenance before execution. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (50)

Tainted flow: 'req' from os.environ.get (line 53, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
}
)
try:
    with urllib.request.urlopen(req, timeout=60) as resp:
        status = getattr(resp, 'status', None)
        resp_text = resp.read().decode('utf-8')
except Exception as e:
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
Accepting an undocumented credential source and dynamically selecting/executing local NodeJS, Python, or Shell implementations introduces hidden trust boundaries. In an agent context, dynamic interpreter selection and undeclared credential handling can lead to unpredictable execution, broader attack surface, and accidental use of the wrong secret source.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
Accepting an undocumented credential source and dynamically selecting/executing local NodeJS, Python, or Shell implementations introduces hidden trust boundaries. In an agent context, dynamic interpreter selection and undeclared credential handling can lead to unpredictable execution, broader attack surface, and accidental use of the wrong secret source.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding
Accepting an undocumented credential source and dynamically selecting/executing local NodeJS, Python, or Shell implementations introduces hidden trust boundaries. In an agent context, dynamic interpreter selection and undeclared credential handling can lead to unpredictable execution, broader attack surface, and accidental use of the wrong secret source.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Accepting an undocumented credential source and dynamically selecting/executing local NodeJS, Python, or Shell implementations introduces hidden trust boundaries. In an agent context, dynamic interpreter selection and undeclared credential handling can lead to unpredictable execution, broader attack surface, and accidental use of the wrong secret source.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
Accepting an undocumented credential source and dynamically selecting/executing local NodeJS, Python, or Shell implementations introduces hidden trust boundaries. In an agent context, dynamic interpreter selection and undeclared credential handling can lead to unpredictable execution, broader attack surface, and accidental use of the wrong secret source.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
Accepting an undocumented credential source and dynamically selecting/executing local NodeJS, Python, or Shell implementations introduces hidden trust boundaries. In an agent context, dynamic interpreter selection and undeclared credential handling can lead to unpredictable execution, broader attack surface, and accidental use of the wrong secret source.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
Accepting an undocumented credential source and dynamically selecting/executing local NodeJS, Python, or Shell implementations introduces hidden trust boundaries. In an agent context, dynamic interpreter selection and undeclared credential handling can lead to unpredictable execution, broader attack surface, and accidental use of the wrong secret source.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
# Reminder for agents/scripts: generated audio files are temporary artifacts.
# Agents/users should remove files in $SKILL_OUT when finished. Example:
#   rm -f "$SKILL_OUT"/*.ogg

# Helper: resolve a script path relative to SKILL_HOME
skill_path() {
Confidence
95% 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
| jq -r '.choices[0].message.audio.data' | base64 -d > "$OUTPUT.wav" || true

if command -v ffmpeg >/dev/null 2>&1; then
  ffmpeg -y -i "$OUTPUT.wav" -acodec libopus -b:a 128k "$OUTPUT" >/dev/null 2>&1 && rm -f "$OUTPUT.wav"
else
  echo "ffmpeg not found; leaving wav at $OUTPUT.wav"
  mv "$OUTPUT.wav" "$OUTPUT"
Confidence
75% confidence
Finding
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Unvalidated Output Injection

High
Category
Output Handling
Content
if MOCK:
    # generate mock silent ogg using ffmpeg if available
    try:
        subprocess.run(['ffmpeg','-f','lavfi','-i','anullsrc=r=16000:cl=mono','-t','0.5','-q:a','9','-acodec','libopus',output,'-y'],check=True,stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
    except Exception:
        open(output,'wb').close()
    print(output)
Confidence
95% confidence
Finding
This mock-mode ffmpeg call has the same argument-injection-by-filename issue: an attacker-controlled output path beginning with '-' can be parsed as an ffmpeg option. In automation or multi-tenant agent environments, that can be abused to alter ffmpeg behavior or write to unexpected locations.

Unvalidated Output Injection

High
Category
Output Handling
Content
# convert wav to ogg if ffmpeg exists
try:
    subprocess.run(['ffmpeg','-y','-i',wav_path,'-acodec','libopus','-b:a','128k',output], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    os.remove(wav_path)
except Exception as e:
    print('ffmpeg conversion failed:', e)
Confidence
95% confidence
Finding
The output filename is user-controlled and passed directly to ffmpeg. Even without shell=True, many CLI tools treat leading-dash arguments as options, so a crafted output value could be interpreted by ffmpeg as an option rather than a filename, potentially causing unintended file writes, overwrites, or other unsafe behavior within the privileges of the running process.

Intent-Code Divergence

High
Confidence
99% confidence
Finding
The shell branch claims to use a shell implementation but actually re-invokes the same wrapper script, creating unbounded recursion whenever NodeJS and Python are unavailable. This can lead to denial of service through repeated process spawning, CPU consumption, and eventual resource exhaustion, and it also prevents the intended TTS function from completing.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The natural-language instructions, usage guidance, and warnings in this file are presented only in Chinese, which effectively forces a specific language for users reading the skill documentation. The file does not offer an alternative language, opt-in, or a documented reason that the skill must be Chinese-only.

Rp1

Medium
Category
MCP Rug Pull
Confidence
90% confidence
Finding
The README instructs users to run `npx @openclaw/skill-runner` without pinning a specific version, which means execution will fetch whatever package version is current at the time. If the upstream package is compromised, replaced, or updated with breaking or malicious behavior, users may execute unreviewed code directly from the registry.

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill documentation describes capabilities that imply environment variable access, network calls, shell execution, and local file writes, but it does not declare any tool scope or permissions. In an agent setting, undeclared execution and I/O surfaces reduce transparency and can lead to over-privileged use or unsafe invocation of external tools and remote services.

External Transmission

Medium
Category
Data Exfiltration
Content
fi

# fallback: simple curl-based request
curl -s -X POST "https://api.xiaomimimo.com/v1/chat/completions" \
  -H "Authorization: Bearer ${XIAOMI_API_KEY}" \
  -H "Content-Type: application/json" \
  -d "$(printf '%s' "{\"model\":\"mimo-v2-tts\",\"messages\":[{\"role\":\"user\",\"content\":\"请朗读\"},{\"role\":\"assistant\",\"content\":\"$TEXT\"}],\"audio\":{\"format\":\"wav\",\"voice\":\"$VOICE\"}}")" \
Confidence
70% 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
95% confidence
Finding
The script sends the provided text to an external API via curl and includes an Authorization header derived from XIAOMI_API_KEY. While there is a dry-run mode, the normal execution path has no visible confirmation prompt, user-facing notice, or explanatory comment warning that user text will be transmitted off-system using credentials.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The script usage example and API prompt include Chinese text ("文本" and "请朗读") and do not indicate that the skill is intentionally limited to Chinese or allow the user to select language/locale behavior. Under SQP-3, forcing a specific language without opt-in can be a policy issue.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The script sends user-provided text to a remote Xiaomi API, which can expose sensitive or proprietary content if users assume processing is local. In a skill context, this is materially relevant because prompts or private text may be forwarded off-host without explicit disclosure or consent flow.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if MOCK:
    # generate mock silent ogg using ffmpeg if available
    try:
        subprocess.run(['ffmpeg','-f','lavfi','-i','anullsrc=r=16000:cl=mono','-t','0.5','-q:a','9','-acodec','libopus',output,'-y'],check=True,stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
    except Exception:
        open(output,'wb').close()
    print(output)
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The script sends arbitrary input text to a third-party remote TTS service over the network, but it provides no explicit warning or consent checkpoint to users at the point of transmission. In agent/automation contexts, this can cause accidental disclosure of secrets, personal data, or sensitive internal content when users may assume processing is local.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# convert wav to ogg if ffmpeg exists
try:
    subprocess.run(['ffmpeg','-y','-i',wav_path,'-acodec','libopus','-b:a','128k',output], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    os.remove(wav_path)
except Exception as e:
    print('ffmpeg conversion failed:', e)
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
This shell script presents all user-facing text, errors, and example invocations in Chinese, which effectively forces a specific language for users interacting with the skill. Under the policy, language constraints should be optional or clearly justified as region-specific; neither is present in this file.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This shell script presents its title, usage guidance, status messages, and errors entirely in Chinese. That imposes a specific language on all users without opt-in, which matches the policy category for language/locale violations.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/base/mimo_tts.js:33

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/smart/mimo_tts_smart.js:16