Back to skill

Security audit

Alibaba Cloud AI Audio TTS Realtime

Security checks for vulnerabilities and agentic risk

Overview

The skill is a mostly coherent Alibaba Cloud TTS helper, but it can send the user's API key and synthesis text to a user-supplied endpoint and then download unvalidated URLs.

Install only if you trust the skill operator and will use the default Alibaba Cloud endpoint. Do not run it with an untrusted --base-url, avoid placing unrelated secrets in .env files where the script can read them, and prefer a narrowly scoped DashScope API key. Treat fallback output paths and downloaded audio as untrusted unless the endpoint is known-good.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/realtime_tts_demo.py:91
Finding
User-Controlled API Endpoint Can Receive Credentials and Synthesis Content<![CDATA[ ## Vulnerability Details **File Location**: `scripts/realtime_tts_demo.py:91-98`, `scripts/realtime_tts_demo.py:158-165`, and `scripts/realtime_tts_demo.py:214` **Vulnerability Type**: Arbitrary credential transmission endpoint **Risk Level**: High ### Vulnerable Code ```python def _probe_realtime( text: str, voice: str, instruction: str | None, language_type: str, base_url: str, ) -> dict[str, Any]: dashscope.base_http_api_url = base_url try: stream = dashscope.MultiModalConversation.call( model=REALTIME_MODEL, api_key=os.getenv("DASHSCOPE_API_KEY"), text=text, voice=voice, instruction=instruction, language_type=language_type, stream=True, ) ``` The fallback path has the same behavior: ```python def _fallback_generate( text: str, voice: str, instruction: str | None, language_type: str, base_url: str, output: Path, ) -> dict[str, Any]: dashscope.base_http_api_url = base_url response = dashscope.MultiModalConversation.call( model=FALLBACK_MODEL, api_key=os.getenv("DASHSCOPE_API_KEY"), text=text, voice=voice, instruction=instruction, language_type=language_type, stream=False, ) ``` The destination is controlled through a command-line argument: ```python parser.add_argument( "--base-url", default="https://dashscope.aliyuncs.com/api/v1", ) ``` ### Technical Analysis The command-line `--base-url` value is assigned directly to the DashScope SDK's global API URL without validating its scheme, hostname, port, or ownership. The script then explicitly supplies `DASHSCOPE_API_KEY` to the SDK request together with the text, voice, language, and synthesis instruction. Although sending an API key to Alibaba Cloud is necessary for the declared TTS functionality, allowing an arbitrary destination exceeds the minimum privilege and trus ...[truncated 1386 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `--base-url` if endpoint customization is not essential. 2. If customization is required, parse the URL and enforce: - The `https` scheme. - An explicit allowlist of documented Alibaba Cloud API hostnames. - No embedded username or password. - No unexpected ports. - No IP-literal, loopback, private, or link-local destinations. 3. Validate the effective destination before loading or passing the API key. 4. Ensure the HTTP client does not follow redirects to destinations outside the allowlist. 5. Prefer a fixed regional endpoint selected through a constrained region enumeration rather than a free-form URL. 6. Avoid global SDK endpoint mutation where possible; use a request-scoped, validated client configuration. 7. Document that API credentials and synthesis text are transmitted only to the approved Alibaba Cloud service. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/realtime_tts_demo.py:77
Finding
Unvalidated Audio URL Enables Server-Side Request Forgery and Unbounded Downloads<![CDATA[ ## Vulnerability Details **File Location**: `scripts/realtime_tts_demo.py:77-80` and `scripts/realtime_tts_demo.py:174-185` **Vulnerability Type**: Unvalidated remote resource retrieval **Risk Level**: Medium ### Vulnerable Code ```python def _download_audio(audio_url: str, output_path: Path) -> None: output_path.parent.mkdir(parents=True, exist_ok=True) with urllib.request.urlopen(audio_url) as response: output_path.write_bytes(response.read()) ``` The URL is taken from the API response and downloaded directly: ```python audio = getattr(response.output, "audio", None) audio_url = audio.get("url") if audio else None if not audio_url: return { "ok": False, "model": FALLBACK_MODEL, "error": "Missing audio_url in response.", } _download_audio(audio_url, output) return { "ok": True, "model": FALLBACK_MODEL, "audio_url": audio_url, "output": str(output), "sample_rate": audio.get("sample_rate") if audio else None, "format": audio.get("format") if audio else None, } ``` ### Technical Analysis The fallback API response controls `audio_url`. The script passes that value directly to `urllib.request.urlopen` without checking the URL scheme, hostname, resolved IP address, redirect destination, response content type, or response size. This behavior can enable server-side request forgery when the API endpoint is malicious or compromised. The process may be induced to request loopback services, private-network hosts, link-local metadata services, or other resources reachable from the user's machine. URL handlers supported by the runtime may also permit access to local resources. The call has no explicit connection or read timeout. `response.read()` loads the entire response into memory before writing it, and there is no maximum byte limit. A malicious or unexpectedly large response can therefore consume excessive memory and disk space. The output path is user-configurable and is written ...[truncated 1612 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Accept only `https` audio URLs. 2. Maintain an explicit allowlist of documented Alibaba-controlled audio delivery hostnames. 3. Resolve the hostname and reject loopback, private, link-local, multicast, reserved, and unspecified addresses. 4. Revalidate the scheme, hostname, port, and resolved address after every redirect, or disable redirects entirely. 5. Set explicit connection and read timeouts. 6. Stream the response in bounded chunks rather than calling `response.read()` without a limit. 7. Enforce a conservative maximum audio size and stop downloading when the limit is exceeded. 8. Validate the response status and require an expected audio content type. 9. Restrict output files to a designated output directory, resolve the final path, and reject path traversal outside that directory. 10. Consider exclusive file creation or require explicit confirmation before overwriting an existing file. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:25
Finding
Unpinned DashScope Dependency Creates Supply-Chain and Reproducibility Risk<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:25-29` **Vulnerability Type**: Unpinned third-party dependency installation **Risk Level**: Low ### Vulnerable Code ```bash python3 -m venv .venv . .venv/bin/activate python -m pip install dashscope ``` ### Technical Analysis The installation instructions request the latest version of `dashscope` available from the active Python package index. No reviewed version, package hash, lock file, or explicit trusted index is specified. Consequently, identical installation commands can resolve to different code over time. A future compromised or malicious release, package-index compromise, or unintended index configuration could cause unreviewed code to be installed and executed when imported by `realtime_tts_demo.py`. The package name appears consistent with the declared Alibaba Cloud SDK, and the audited project does not contain evidence that it intentionally selects a typosquatted package. The finding concerns the absence of version and integrity controls rather than a confirmed malicious dependency. ### Attack Path 1. A user follows the documented `pip install dashscope` command. 2. Pip resolves the package using the user's configured package index and selects the latest compatible release. 3. A compromised future release, compromised index, or malicious package served by an unintended index is downloaded. 4. Package installation hooks or imported package code execute with the permissions of the user running pip or the demo. 5. The dependency can access files, environment variables, and credentials available to that process, including `DASHSCOPE_API_KEY`. ### Impact Assessment Malicious dependency code would execute with the operating-system permissions of the installing or running user. It could access project files, environment variables, the Alibaba Cloud credential available to the process, and network resources reachable from the host. The virtual environment limits Python package placeme ...[truncated 126 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `dashscope` to a specifically reviewed version. 2. Store dependencies in a requirements or lock file. 3. Use hash verification, for example pip's `--require-hashes`, with reviewed distribution hashes. 4. Document and enforce the official trusted package index. 5. Review dependency updates before changing the pinned version. 6. Use automated vulnerability and provenance checks in CI. 7. Install and run the dependency under a minimally privileged user and avoid exposing unrelated credentials to the process. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (9)

Tainted flow: 'audio_url' from os.getenv (line 186, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
def _download_audio(audio_url: str, output_path: Path) -> None:
    output_path.parent.mkdir(parents=True, exist_ok=True)
    with urllib.request.urlopen(audio_url) as response:
        output_path.write_bytes(response.read())
Confidence
95% confidence
Finding
The script downloads a URL returned by the remote TTS API and passes it directly to urllib.request.urlopen without validating the scheme, host, or destination. If that URL is malicious or the upstream service is compromised, this can enable server-side request forgery or unintended access to local/internal resources, especially because urllib may support non-HTTP schemes in some environments.

Credential Access

High
Category
Privilege Escalation
Content
def _load_env() -> None:
    _load_dotenv(Path.cwd() / ".env")
    repo_root = _find_repo_root(Path(__file__).resolve())
    if repo_root:
        _load_dotenv(repo_root / ".env")
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
def _load_env() -> None:
    _load_dotenv(Path.cwd() / ".env")
    repo_root = _find_repo_root(Path(__file__).resolve())
    if repo_root:
        _load_dotenv(repo_root / ".env")
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill documents executable scripts, network access, filesystem writes, and use of environment-based credentials, but does not declare any explicit tool scope or permissions boundaries. This creates unnecessary ambiguity about what the skill is allowed to do and can lead to over-privileged execution in agent environments, increasing the chance of unintended network calls, secret access, or file modification.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The manifest positions this skill as real-time speech synthesis for low-latency interactive use, but the script explicitly supports a non-realtime fallback path and writes the resulting audio to disk. That behavior is broader than a pure realtime TTS skill and changes the operational scope from interactive synthesis to offline artifact generation.

Missing User Warnings

Low
Confidence
88% confidence
Finding
The skill tells users to provide credentials via an environment variable or local credentials file but gives no guidance on secure storage, least exposure, or avoiding accidental disclosure in logs and artifacts. In a skill that also writes outputs and evidence files, this omission increases the risk of credential leakage through misconfiguration or operator error.

Intent-Code Divergence

Low
Confidence
92% confidence
Finding
The manifest and the rest of the file describe a narrowly scoped realtime text-to-speech skill, but the workflow section instructs operators to confirm region, identifiers, whether an operation is read-only or mutating, and to run a minimal read-only query first. Those instructions are generic cloud-operations guidance and actively misdescribe the intended behavior of TTS synthesis, which is neither a read-only query workflow nor a mutating resource operation.

Natural-Language Policy Violations

Low
Confidence
94% confidence
Finding
The code sets `DEFAULT_LANGUAGE = "Chinese"`, and this default is then used for the `--language-type` argument unless the user overrides it. This imposes a language/locale choice by default rather than prompting for or documenting explicit user opt-in.

Context-Inappropriate Capability

Low
Confidence
83% confidence
Finding
In addition to performing TTS requests, the code searches for .env files and reads ~/.alibabacloud/credentials to populate the API key automatically. While useful for convenience, credential discovery from local config files is not implied by the manifest's user-facing purpose of realtime speech synthesis.

Static analysis

No suspicious patterns detected.