Back to skill

Security audit

Chanjing Tts Voice Clone

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to provide the advertised voice-clone TTS workflow, but it has under-scoped credential handling that could send secrets to an environment-controlled API endpoint.

Install only if you trust the publisher and your execution environment. Keep CHANJING_API_BASE unset unless you intentionally use a trusted HTTPS Chanjing endpoint, keep CHANJING_CONFIG_DIR in a private user-owned directory, protect credentials.json from backups or commits, and understand that reference-audio URLs, synthesis text, tokens, and task identifiers are sent to the configured API service.

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

Error
Location
scripts/_auth.py:13
Finding

Unrestricted API Base Override Can Redirect Credentials and User Data

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/_auth.py:48
Finding

Credential File Is Written Without Enforced Owner-Only Permissions

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
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (34)

Tainted flow: 'req' from os.environ.get (line 75, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
95% confidence
Finding

The request destination is derived from CHANJING_API_BASE, so environment control can silently redirect app_id and secret_key to an arbitrary server. Because this function posts long-lived credentials to obtain a token, misuse would directly leak secrets and enable unauthorized API access.

Content

Scanner excerpt · scripts/_auth.py (reported line 82)May include surrounding context.

python
method="POST",
    )
    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            body = json.loads(resp.read().decode("utf-8"))
    except Exception as e:
        return None, str(e)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description says the skill's primary purpose is TTS synthesis from text using a user-provided voice. However, this code chunk's actual purpose is voice creation/customized audio cloning from a reference audio URL. It accepts a name, URL, model type, and language; obtains an access token; calls the create_customised_audio API endpoint; and prints the returned voice_id. While some details align with the description—shared credential handling, optional CHANJING_API_BASE, and use of a public URL for reference audio—the core behavior is materially different from text-to-speech synthesis. Therefore this is a description-to-behavior mismatch.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
87% confidence
Finding

The skill explicitly states that access_token and expire_in are written back into the same credentials.json file, increasing secret persistence on disk and the blast radius if that file is read by another process or accidentally disclosed. Co-locating long-lived app credentials and refreshed bearer tokens in one writable file is riskier than minimizing token persistence or isolating token storage.

Content

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

md
## 功能说明

基于用户提供的**参考音频公网 URL**(由蝉镜服务端拉取)创建音色并合成语音;轮询任务并从接口返回 URL 下载结果。脚本**不**依赖 ffmpeg/ffprobe。机器可读凭据声明见篇首 **`metadata.openclaw.credentialModel`**。**`access_token` 与 `expire_in` 会写入同一 `credentials.json`;刷新令牌时由本技能覆盖文件中对应字段,请勿将凭证提交到版本库。**

## 运行依赖

Credential Access

High
Category
Privilege Escalation
Confidence
87% confidence
Finding

This line confirms that app credentials and refreshed access tokens are both read and written in the same disk file, with overwrite behavior on refresh. Persistent writable storage of bearer tokens alongside root API secrets increases the chance of credential theft, accidental backup leakage, or misuse by other local tooling.

Content

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

md
## 登记摘要(英文 · ClawHub / OpenClaw)

**Primary credential (not `primaryEnv`)**: `app_id` + `secret_key` in `~/.chanjing/credentials.json` (or `$CHANJING_CONFIG_DIR/credentials.json`); `access_token` and `expire_in` **read/written** in the same file (**overwritten** on token refresh). **`primaryEnv` omitted** by design. **`metadata.openclaw.credentialModel`** is the machine-readable registry source of truth.

**Required vs optional**: **`CHANJING_API_BASE`** **optional** (default `https://open-api.chanjing.cc`). **`CHANJING_CONFIG_DIR`** optional. **No** `ffmpeg`/`ffprobe` in skill `metadata`.

Credential Access

High
Category
Privilege Escalation
Confidence
78% confidence
Finding

The runtime scope explicitly includes reading and writing credentials and trusting both user-provided URLs and API-returned URLs. While legitimate for functionality, this combination materially increases exposure because secrets are handled locally and network retrieval is influenced by external inputs.

Content

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

md
| # | Topic | Answer |
|---|-------|--------|
| **1** | **Purpose vs implementation; primary credential** | **Aligned**. **Voice-clone TTS** client; **reference audio via user-provided public URL** (server-side fetch). **`CHANJING_API_BASE` not required**. **Primary credential** in **`credentials.json`**; **`primaryEnv` omitted**. **No** `ffmpeg`/`ffprobe` in `metadata`. |
| **2** | **Runtime scope: secrets, URLs** | **In scope**. **Read/write** credentials; **browser** if needed; **HTTPS**; **user reference URL** + **output URLs from API**—trust boundaries include **user-chosen reference URL** and **API host**. |
| **3** | **Env vs file secrets** | **`CHANJING_*`** optional; **`app_id` / `secret_key` / `access_token` / `expire_in` on disk**—sensitive; token fields **overwritten** on refresh. |
| **4** | **Persistence & privilege** | **`always: false`** default; **does not** modify other skills or global agent config. |

Credential Access

High
Category
Privilege Escalation
Confidence
86% confidence
Finding

The documented behavior persists and overwrites access_token and expire_in in a general credentials file under a configurable directory. Configurable secret locations plus token persistence can be dangerous if the environment variable is manipulated or points to an insecure/shared location.

Content

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

md
| Aspect | Details |
|--------|---------|
| **Primary credential** | Same file-based `app_id` / `secret_key` as other Chanjing skills. **Not** `primaryEnv`. |
| **Token** | Refreshed and **written** to `~/.chanjing/credentials.json` (or `CHANJING_CONFIG_DIR`); **`access_token` and `expire_in` are overwritten** when the skill refreshes the token. |
| **Env** | Optional `CHANJING_API_BASE`, `CHANJING_CONFIG_DIR`. |
| **User-supplied URL** | Create Voice API takes a **public URL** to reference audio; the user is responsible for that URL’s safety and legality; Chanjing’s servers retrieve it. |
| **Network / browser** | HTTPS to `https://open-api.chanjing.cc`; may open login when credentials are missing. |

Credential Access

High
Category
Privilege Escalation
Confidence
74% confidence
Finding

The workflow requires obtaining and then using an access token for multiple subsequent requests, indicating session-bearing credentials are handled across steps. In this skill context, that becomes more sensitive because token persistence is elsewhere documented as on-disk and refreshed automatically.

Content

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

md
5. Poll the Query Speech Generation Task Status API until the result is success
6. When the task status is complete, use the corresponding url in API response to download the generated audio file

### Get Access Token API

从 `~/.chanjing/credentials.json` 读取 `app_id` 和 `secret_key`,若无有效 Token 则调用:

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

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

md
# 鉴权:与 chanjing-credentials-guard 使用同一配置文件(CONFIG_DIR/credentials.json)
# 无 AK/SK 时执行 open_login_page.py 打开注册/登录页
import json
import os

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

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

md
# 鉴权:与 chanjing-credentials-guard 使用同一配置文件(CONFIG_DIR/credentials.json)
# 无 AK/SK 时执行 open_login_page.py 打开注册/登录页
import json
import os

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

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

md
# 鉴权:与 chanjing-credentials-guard 使用同一配置文件(CONFIG_DIR/credentials.json)
# 无 AK/SK 时执行 open_login_page.py 打开注册/登录页
import json
import os

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

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

md
# 鉴权:与 chanjing-credentials-guard 使用同一配置文件(CONFIG_DIR/credentials.json)
# 无 AK/SK 时执行 open_login_page.py 打开注册/登录页
import json
import os

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

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

md
# 鉴权:与 chanjing-credentials-guard 使用同一配置文件(CONFIG_DIR/credentials.json)
# 无 AK/SK 时执行 open_login_page.py 打开注册/登录页
import json
import os

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

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

md
# 鉴权:与 chanjing-credentials-guard 使用同一配置文件(CONFIG_DIR/credentials.json)
# 无 AK/SK 时执行 open_login_page.py 打开注册/登录页
import json
import os

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

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

md
# 鉴权:与 chanjing-credentials-guard 使用同一配置文件(CONFIG_DIR/credentials.json)
# 无 AK/SK 时执行 open_login_page.py 打开注册/登录页
import json
import os

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

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

md
# 鉴权:与 chanjing-credentials-guard 使用同一配置文件(CONFIG_DIR/credentials.json)
# 无 AK/SK 时执行 open_login_page.py 打开注册/登录页
import json
import os

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · scripts/_auth.py (reported line 1)May include surrounding context.

python
# 鉴权:与 chanjing-credentials-guard 使用同一配置文件(CONFIG_DIR/credentials.json)
# 无 AK/SK 时执行 open_login_page.py 打开注册/登录页
import json
import os

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · scripts/_auth.py (reported line 12)May include surrounding context.

python
# 鉴权:与 chanjing-credentials-guard 使用同一配置文件(CONFIG_DIR/credentials.json)
# 无 AK/SK 时执行 open_login_page.py 打开注册/登录页
import json
import os

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
84% confidence
Finding

The skill declares significant capabilities in practice—environment access, reading and writing credentials, network access, and shell/script execution—but does not declare an explicit tool scope such as permissions or allowed-tools. This weakens policy enforcement and reviewability, making it easier for an agent runtime to grant broader powers than users or reviewers expect.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
76% confidence
Finding

The documented workflow requires retaining a voice ID and task ID across polling steps, reflecting session/state persistence. In this skill that state is tied to credentialed API operations and culminates in downloading from API-returned URLs, so weak handling of persisted identifiers can enable unintended reuse, leakage in logs, or confusion across users/jobs.

Content

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

md
You should use utf-8 to encode and decode text throughout this task.

1. Obtain an access\_token, which is required for subsequent requests
2. Call the Create Voice API, which accepts a url to an audio file as reference voice
3. Poll the Query Voice API until the result is success; keep the voice ID
4. Call the Create Speech Generation Task API, using the voice ID, record the `task_id`
5. Poll the Query Speech Generation Task Status API until the result is success

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Comments, docstrings, and the user-facing NO_CREDENTIALS_MSG are written only in Chinese, which imposes a specific language on users without opt-in or alternative locale support. This matches the language-policy violation category because the file contains user-visible text that assumes a single language.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/_auth.py (reported line 29)May include surrounding context.

python
skills_dir = Path(__file__).resolve().parent.parent.parent
        script = skills_dir / "chanjing-credentials-guard" / "scripts" / "open_login_page.py"
        if script.exists():
            subprocess.run([sys.executable, str(script)], check=False, timeout=5)
        else:
            import webbrowser
            webbrowser.open(LOGIN_URL)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The function writes sensitive authentication data to credentials.json, and later stores the refreshed access token there as well. In this file there is no confirmation prompt, logging, or warning comment disclosing that credentials and tokens are persisted locally.

Content

No source excerpt is available for this finding.

Tainted flow: 'CONFIG_FILE' from os.environ.get (line 12, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
84% confidence
Finding

The config file path is influenced by the CHANJING_CONFIG_DIR environment variable and then written without validation. In a hostile execution environment, this could redirect credential and token writes to an attacker-chosen location, causing secret exposure, overwriting other files accessible to the process, or unsafe symlink-following behavior.

Content

Scanner excerpt · scripts/_auth.py (reported line 50)May include surrounding context.

python
def write_config(data):
    CONFIG_DIR.mkdir(parents=True, exist_ok=True)
    with open(CONFIG_FILE, "w", encoding="utf-8") as f:
        json.dump(data, f, indent=2, ensure_ascii=False)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The code performs an HTTP POST to /open/v1/access_token containing the user's app_id and secret_key. Although this is part of authentication, the file provides no user-facing disclosure, prompt, or logging that credentials will be transmitted to the remote service.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The docstring and usage text require Chinese to understand how to invoke the script and what it does. This imposes a language constraint without any user opt-in or alternative locale, which matches the language/locale policy violation category.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.