Back to skill

Security audit

Mybooks tts

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent MyBooks TTS admin tool, but it needs review because it handles administrator credentials and can make persistent or destructive changes with weak safeguards.

Install only if you trust the MyBooks server and need an admin-level automation tool. Use HTTPS with certificate verification enabled, avoid storing admin credentials in shared environment files, review delete actions manually, and do not allow untrusted prompts or automation to choose local save paths.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mybooks_tts_api.py:31
Finding

Administrator Credentials and API Keys May Be Transmitted over an Untrusted Transport

Content
View full analysis

Vulnerability Details

File Location: scripts/mybooks_tts_api.py:31, 98, 108-121, 139-149; SKILL.md:14-17
Vulnerability Type: Configurable plaintext transport and optional TLS certificate-verification bypass
Risk Level: Medium

Vulnerable Code

python
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
python
self.verify_ssl = os.environ.get("MYBOOKS_SSL_VERIFY", "true").lower() in ("true", "1", "yes")
python
def sign_in(self) -> None:
    """Authenticate with the server and store session cookies."""
    url = f"{self.host}/api/user/sign_in"
    data = f"username={self.username}&password={self.password}"

    try:
        resp = self.requests.post(
            url,
            data=data,
            headers={"Content-Type": "application/x-www-form-urlencoded"},
            timeout=30,
            verify=self.verify_ssl
        )
        resp.raise_for_status()
        result = resp.json()
python
url = f"{self.host}{path}"
kwargs.setdefault('cookies', self.session_cookies)
kwargs.setdefault('timeout', 30)
kwargs.setdefault('verify', self.verify_ssl)

try:
    resp = self.requests.request(method, url, **kwargs)

The documentation actively demonstrates configurations that use plaintext HTTP and disable certificate verification:

bash
export MYBOOKS_HOST="http://127.0.0.1:8082"
export MYBOOKS_USER="admin"
export MYBOOKS_PASSWORD="your_password"
export MYBOOKS_SSL_VERIFY="false"   # For a self-signed server certificate

Technical Analysis

The client sends an administrator username and password to the configured MYBOOKS_HOST, retains authenticated session cookies, and subsequently sends those cookies with every API request. Configuration and conversion operations can also transmit a third-party TTS API key.

TLS verification defaults to enabled, but the user can disable it through `MYBOOKS_SSL ...[truncated 2523 chars]

Remediation
View remediation

Remediation Suggestions

  1. Require https:// for every non-loopback host. Reject plaintext HTTP unless the parsed host is an actual loopback address such as 127.0.0.1 or ::1.
  2. Do not permit certificate verification to be disabled for remote hosts. For self-signed deployments, accept a path to a trusted private CA bundle and pass that path through verify.
  3. Remove the global suppression of InsecureRequestWarning. If an exceptional insecure mode remains available, emit a prominent warning for every invocation.
  4. Validate the final parsed URL, including scheme, hostname, and port, rather than relying on string-prefix checks.
  5. Encode login credentials using the request library:
    python
    resp = self.requests.post(
        url,
        data={"username": self.username, "password": self.password},
        timeout=30,
        verify=self.verify_ssl,
    )
    
  6. Prefer short-lived, narrowly scoped API tokens over reusable administrator passwords where the server supports them.
  7. Update the documentation to demonstrate HTTPS by default and clearly restrict any HTTP example to a loopback-only development deployment.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mybooks_tts_api.py:340
Finding

Arbitrary Writable-Path Overwrite through the Clone-Audio Download Tool

Content
View full analysis

Vulnerability Details

File Location: scripts/mybooks_tts_api.py:340-379
Vulnerability Type: Unrestricted file write, existing-file overwrite, and symlink following
Risk Level: Medium

Vulnerable Code

python
save_to = args.get("save_to", "")
query = urllib.parse.urlencode({"voice_name": voice_name})

url = f"{self.host}{API_PREFIX}/clone/audio?{query}"
kwargs = {
    'cookies': self.session_cookies,
    'timeout': 60,
    'verify': self.verify_ssl,
}

try:
    resp = self.requests.get(url, **kwargs)

    # Check for auth redirect
    try:
        ct = resp.headers.get('Content-Type', '')
        if 'json' in ct:
            result = resp.json()
            if result.get("err") == "user.need_login":
                self.sign_in()
                kwargs['cookies'] = self.session_cookies
                resp = self.requests.get(url, **kwargs)
                ct = resp.headers.get('Content-Type', '')
                if 'json' in ct:
                    return resp.json()
    except Exception:
        pass

    content = resp.content

    if save_to:
        with open(save_to, 'wb') as f:
            f.write(content)
        return {
            "err": "ok",
            "msg": "Audio saved",
            "path": save_to,
            "size": len(content),
        }
    else:
        # Return base64 for small files
        b64 = base64.b64encode(content).decode('ascii')
        return {
            "err": "ok",
            "msg": "Audio retrieved",
            "voice_name": voice_name,
            "size": len(content),
            "base64": b64,
        }

Technical Analysis

The tts_clone_audio operation accepts an unrestricted save_to value and opens that path with mode wb. This mode creates a missing file or truncates an existing file. It also follows symbolic links. No canonical-path validation, destination-directory restricti ...[truncated 2207 chars]

Remediation
View remediation

Remediation Suggestions

  1. Restrict downloads to a dedicated application-controlled directory instead of accepting arbitrary absolute paths.
  2. Resolve the canonical destination with Path.resolve() and verify that it remains beneath the approved output directory.
  3. Reject symbolic-link destinations and inspect all relevant parent components where appropriate.
  4. Refuse to overwrite an existing file by default. Use exclusive creation, such as mode xb, and require a separate explicit overwrite option if replacement is genuinely needed.
  5. Generate safe filenames from server-side voice identifiers instead of allowing callers to choose the complete path.
  6. Call resp.raise_for_status() before accessing or writing the response body.
  7. Enforce an expected response content type and validate the audio file signature before committing it to disk.
  8. Apply a response-size limit and stream the download into a temporary file inside the approved directory.
  9. After validation, atomically rename the temporary file to its final destination.
  10. Run the Skill under a dedicated, unprivileged account with write access limited to its output directory.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (10)

Lp1

High
Category
MCP Least Privilege
Confidence
95% confidence
Finding

This code makes authenticated HTTP(S) requests to a configurable host supplied via environment variables, creating a broad network capability. In skill-based systems, failing to declare network access is a real security issue because it bypasses operator expectations and weakens containment, especially since the account used must be an administrator.

Content

No source excerpt is available for this finding.

Lp1

High
Category
MCP Least Privilege
Confidence
95% confidence
Finding

This code makes authenticated HTTP(S) requests to a configurable host supplied via environment variables, creating a broad network capability. In skill-based systems, failing to declare network access is a real security issue because it bypasses operator expectations and weakens containment, especially since the account used must be an administrator.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 76)May include surrounding context.

md
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `api_url` | string | ✅ | API 地址,如 `https://api.xiaomimimo.com/v1/chat/completions` |
| `model_name` | string | ✅ | 模型 ID,MiMo TTS 类型固定为 `mimo-v2.5-tts` |
| `api_type` | string | ✅ | API 类型:`chat_completions`(MiMo TTS)/ `audio_speech`(OpenAI 兼容)/ `custom` |
| `api_key` | string | ✅ | API 密钥 |

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 87)May include surrounding context.

md
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `api_url` | string | ✅ | API 地址,如 `https://api.xiaomimimo.com/v1/chat/completions` |
| `model_name` | string | ✅ | 模型 ID,MiMo TTS 类型固定为 `mimo-v2.5-tts` |
| `api_type` | string | ✅ | API 类型:`chat_completions`(MiMo TTS)/ `audio_speech`(OpenAI 兼容)/ `custom` |
| `api_key` | string | ✅ | API 密钥 |

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 152)May include surrounding context.

md
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `api_url` | string | ✅ | API 地址,如 `https://api.xiaomimimo.com/v1/chat/completions` |
| `model_name` | string | ✅ | 模型 ID,MiMo TTS 类型固定为 `mimo-v2.5-tts` |
| `api_type` | string | ✅ | API 类型:`chat_completions`(MiMo TTS)/ `audio_speech`(OpenAI 兼容)/ `custom` |
| `api_key` | string | ✅ | API 密钥 |

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill documents destructive admin operations such as deleting clone voices and deleting prompts, but does not require a confirmation step or warn the operator before execution. In an LLM-agent workflow, this creates a real risk of unintended deletion from ambiguous prompts, mis-parsing, or prompt injection via surrounding conversation context.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The invocation guide maps broad natural-language phrases like '开始转换', '连接正常吗', or '删除提示词' directly to privileged admin actions. In an agent setting, this increases the chance of accidental tool execution from ordinary conversation or ambiguous user requests, especially because all operations require admin privileges and some actions are state-changing or destructive.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The tts_clone_delete method issues a delete-style API operation against stored clone voices, but the implementation provides no confirmation prompt, logging, or explicit user-facing disclosure at the point of execution. For a destructive action that removes user-managed data, this file lacks an in-code warning beyond the method name and parameter description.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The tts_prompt_delete method deletes saved voice prompts via an API call, but there is no confirmation prompt, print/log disclosure, or explicit warning that the action removes existing data. This makes a destructive operation easy to invoke without any visible safety disclosure in the code file.

Content

No source excerpt is available for this finding.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/mybooks_tts_api.py (reported line 446)May include surrounding context.

python
Returns:
            Tool execution result
        """
        tool_method = getattr(self, tool_name, None)

        if tool_method is None or not callable(tool_method):
            return {