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

Content
View full analysis
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
View remediation

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

Content
View full analysis
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
View remediation

T08 · Insecure Dependencies

Note
Location
SKILL.md:25
Finding

Unpinned DashScope Dependency Creates Supply-Chain and Reproducibility Risk

Content
View full analysis
Remediation
View remediation
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
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.

Content

Scanner excerpt · scripts/realtime_tts_demo.py (reported line 83)May include surrounding context.

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

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/realtime_tts_demo.py (reported line 54)May include surrounding context.

python
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")

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/realtime_tts_demo.py (reported line 57)May include surrounding context.

python
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")

Undeclared Tool Scope

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.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.