Back to skill

Security audit

Chanjing Video Compose

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it says, but it handles persistent API secrets and unvalidated URLs in ways that deserve careful review before installation.

Install only if you are comfortable storing Chanjing app credentials and access tokens in ~/.chanjing/credentials.json. Do not set CHANJING_API_BASE unless you fully trust the endpoint, avoid shared machines or permissive config directories, verify callback and media URLs, and be cautious with custom download output paths because files can be overwritten.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/_auth.py:11
Finding
Environment-Controlled API Base Can Exfiltrate Application Credentials and Access Tokens<![CDATA[ ## Vulnerability Details **File Location**: `scripts/_auth.py:11-13, 76-84`; authenticated requests are also issued through the same configurable base in `scripts/list_figures.py`, `scripts/upload_file.py`, `scripts/create_task.py`, and `scripts/poll_task.py` **Vulnerability Type**: Unvalidated authentication endpoint **Risk Level**: High ### Vulnerable Code ```python CONFIG_DIR = Path(os.environ.get("CHANJING_CONFIG_DIR", Path.home() / ".chanjing")) CONFIG_FILE = CONFIG_DIR / "credentials.json" API_BASE = os.environ.get("CHANJING_API_BASE", "https://open-api.chanjing.cc") ``` ```python url = API_BASE + "/open/v1/access_token" req = urllib.request.Request( url, data=json.dumps({"app_id": app_id, "secret_key": secret_key}).encode("utf-8"), headers={"Content-Type": "application/json"}, method="POST", ) try: with urllib.request.urlopen(req, timeout=30) as resp: body = json.loads(resp.read().decode("utf-8")) ``` ### Technical Analysis `CHANJING_API_BASE` completely controls the destination used to obtain an access token. The value is not checked for an approved hostname, HTTPS, an expected port, embedded credentials, or another safe deployment policy. When a cached token is unavailable or near expiry, `get_token()` sends the long-lived `app_id` and `secret_key` directly to this endpoint. The other scripts similarly attach `access_token` to requests constructed from the same environment-controlled base. Supporting alternate API deployments can be legitimate, but forwarding production credentials to any environment-selected destination exceeds safe minimum privilege. It also permits plaintext transmission if the configured URL uses HTTP. ### Attack Path 1. An attacker influences the environment inherited by the Skill process, its wrapper, job runner, or shell. 2. The attacker sets `CHANJING_API_BASE` to an attacker-controlled HTTP or HTTPS endpoint. 3. The user invokes an authenticated operation such as listing figures, u ...[truncated 936 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require `https` for all credential-bearing endpoints and reject plaintext HTTP. 2. Allowlist `open-api.chanjing.cc` as the default and expected production hostname. 3. If custom deployments are required, use an explicit trusted-host configuration rather than accepting an unrestricted environment value. 4. Reject URLs containing user information, fragments, unexpected ports, or malformed hostnames. 5. Validate redirect destinations so credentials or bearer tokens cannot be redirected to an untrusted host. 6. Do not reuse production credentials automatically when a custom endpoint is configured. Maintain separate credentials scoped to each approved endpoint. 7. Consider requiring explicit user confirmation before sending secrets to any non-default host. 8. Document the endpoint trust model and fail closed when validation fails. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/_auth.py:50
Finding
Credential File Permissions Are Not Explicitly Restricted<![CDATA[ ## Vulnerability Details **File Location**: `scripts/_auth.py:50-53` **Vulnerability Type**: Insecure local secret storage **Risk Level**: Medium ### Vulnerable Code ```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) ``` ### Technical Analysis The configuration file stores `app_id`, `secret_key`, `access_token`, and token-expiry data. The code creates the directory and writes the file without explicitly enforcing restrictive permissions. Actual permissions therefore depend on the process umask and any permissions already present on the directory or file. Under a permissive umask, the credential file may be readable by other local users. Reopening an existing file does not repair insecure permissions. The direct write also lacks atomic replacement. A failure during serialization or writing could leave a partially written credential file. Moreover, no protection is applied against an existing configuration path being a symbolic link. ### Attack Path 1. The Skill runs under a permissive umask, or `credentials.json` already has overly broad permissions. 2. Token acquisition or refresh invokes `write_config()`. 3. The script writes the application credentials and refreshed access token without correcting permissions. 4. Another local account or process with filesystem access reads the file. 5. The exposed credentials are reused to access the Chanjing account. A local attacker who can replace the configuration path with a suitable symbolic link may also be able to redirect the write, depending on directory ownership and filesystem permissions. ### Impact Assessment A local attacker may obtain both long-lived application credentials and the persisted bearer token. The resulting external-service privileges are those assigned to the Chanjing account. The default location under the user's home directory red ...[truncated 226 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create the configuration directory with mode `0700` and correct existing directory permissions where appropriate. 2. Create the credential file with mode `0600`, using low-level flags such as `os.open()` with an explicit mode. 3. Verify and repair permissions on an existing credential file before reading or rewriting it. 4. Write to a securely created temporary file in the same directory, flush and synchronize it, set mode `0600`, and atomically replace the destination. 5. Reject symbolic links and unexpected non-regular files. Where supported, use `O_NOFOLLOW`. 6. Verify that the configuration directory and file are owned by the expected user. 7. Avoid persisting the access token when secure platform credential storage is available. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/download_result.py:26
Finding
Unrestricted Download URL and Output Path Permit Local Resource Access and Arbitrary File Overwrite<![CDATA[ ## Vulnerability Details **File Location**: `scripts/download_result.py:26-31, 37-52` **Vulnerability Type**: Unrestricted URL retrieval and arbitrary writable-path overwrite **Risk Level**: High ### Vulnerable Code ```python def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="下载蝉镜视频合成结果到本地目录") parser.add_argument("--url", required=True, help="video_url") parser.add_argument( "--output", help="输出文件路径;默认保存到 outputs/video-compose/<文件名>", ) return parser.parse_args() ``` ```python args = parse_args() default_dir = Path("outputs") / "video-compose" output_path = Path(args.output) if args.output else default_dir / infer_filename(args.url) output_path.parent.mkdir(parents=True, exist_ok=True) req = urllib.request.Request( args.url, headers={"User-Agent": "chanjing-video-compose-downloader"}, method="GET", ) try: with urllib.request.urlopen(req, timeout=120) as resp, open(output_path, "wb") as handle: handle.write(resp.read()) ``` ### Technical Analysis The downloader accepts any URL understood by `urllib.request` and does not require HTTPS or a trusted media host. It also does not validate redirect destinations. Depending on available URL handlers and runtime behavior, this can permit access to local resources or internal network services rather than only downloading a Chanjing result. The `--output` argument accepts any path writable by the current process. Opening the path with `"wb"` truncates an existing file. The script neither confines output to `outputs/video-compose` nor checks for symbolic links, existing files, or sensitive destinations. Finally, `resp.read()` loads the complete response into memory before writing it. There is no content-length policy or maximum download size, allowing a large or unbounded response to exhaust memory or disk space. Although documentation says downloading should occur only after explicit user approval, that workfl ...[truncated 1601 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Accept only HTTPS URLs. 2. Validate the initial URL and every redirect destination. 3. Allowlist documented Chanjing media domains or cryptographically trusted storage domains where feasible. 4. Resolve destination hostnames and reject loopback, unspecified, link-local, private, multicast, and cloud metadata addresses unless explicitly required. 5. Confine downloads to a fixed output root such as `outputs/video-compose`. 6. Resolve the destination path and verify that it remains beneath the approved output directory. 7. Reject symbolic links and non-regular destination files. 8. Refuse to overwrite existing files unless the user provides a separate explicit overwrite flag. 9. Stream the response in bounded chunks instead of calling `resp.read()` without a size. 10. Enforce a maximum response size and validate expected media content types. 11. Write to a temporary file and atomically rename it only after a successful, validated download. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/upload_file.py:90
Finding
API-Supplied Upload URL Is Trusted Without Scheme or Host Validation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/upload_file.py:90-108` **Vulnerability Type**: Unvalidated external upload destination **Risk Level**: Medium ### Vulnerable Code ```python data = body.get("data", {}) sign_url = data.get("sign_url") mime_type = data.get("mime_type", "application/octet-stream") file_id = data.get("file_id") if not sign_url or not file_id: print("响应缺少 sign_url 或 file_id", file=sys.stderr) sys.exit(1) with open(path, "rb") as f: content = f.read() put_req = urllib.request.Request( sign_url, data=content, headers={"Content-Type": mime_type}, method="PUT", ) try: with urllib.request.urlopen(put_req, timeout=120) as put_resp: ``` ### Technical Analysis The upload workflow legitimately requires a signed storage URL returned by the Chanjing API. However, the returned `sign_url` is used without validating its scheme, hostname, port, or redirect behavior. If the API endpoint is malicious, compromised, misconfigured, or redirected through the environment-controlled `CHANJING_API_BASE`, it can return an attacker-controlled upload URL. The script then sends the complete user-selected audio or background file to that destination. The file is also read completely into memory before upload. No file-size limit or streaming mechanism is applied, creating avoidable memory-exhaustion risk for large inputs. ### Attack Path 1. An attacker controls or compromises the configured API endpoint, or exploits the unrestricted `CHANJING_API_BASE` setting. 2. The user invokes `upload_file.py` with a local audio, image, or other accepted file. 3. The attacker-controlled API returns a successful response containing an attacker-owned `sign_url`. 4. The script reads the entire selected file into memory. 5. The script performs a `PUT` request to the unvalidated URL. 6. The attacker receives the user-selected media file. A sufficiently large file can also cause excessive memory use before transmission. ### Imp ...[truncated 510 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require signed upload URLs to use HTTPS. 2. Maintain an allowlist of documented Chanjing storage domains and reject unexpected hosts or ports. 3. Validate every redirect target and prohibit redirects to untrusted hosts. 4. Bind trusted upload-host policy to the configured API deployment so one environment cannot authorize arbitrary destinations. 5. Display or log the validated destination hostname before transferring sensitive media. 6. Stream files in bounded chunks rather than loading the entire file into memory. 7. Enforce an appropriate maximum upload size before opening or transmitting the file. 8. Optionally verify file type using content inspection rather than relying only on the selected service and server-provided MIME type. 9. Fail closed if the signed URL cannot be parsed or does not meet the configured trust policy. ]]>
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 77, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
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)
Confidence
97% confidence
Finding
The request target is built from CHANJING_API_BASE, an environment-controlled value, and the POST body contains app_id and secret_key. If this environment variable is set to an attacker-controlled endpoint, the skill will exfiltrate long-lived API credentials directly to that server over the network.

Credential Access

High
Category
Privilege Escalation
Content
## 登记摘要(英文 · ClawHub / OpenClaw)

**Primary credential (not `primaryEnv`)**: `app_id` + `secret_key` in `~/.chanjing/credentials.json` (or `$CHANJING_CONFIG_DIR/credentials.json`); `access_token` / expiry **read/written** in the same file. **`primaryEnv` is omitted** on purpose (OpenClaw uses it for a single env-injected API key; this client uses **file-based dual keys**).

**Required vs optional**: **`CHANJING_API_BASE`** is **optional** (defaults to `https://open-api.chanjing.cc`). **`CHANJING_CONFIG_DIR`** is optional. **No `ffmpeg` / `ffprobe` gate** in this skill's `metadata`—orchestration-only use of this skill does not bundle local concat.
Confidence
83% confidence
Finding
This section documents that access tokens and expiry are read from and written back to the same plaintext credentials file on disk. Persisting live bearer tokens in a shared file increases exposure if local filesystem permissions are weak, backups are accessible, or other skills/processes can read the same file.

Credential Access

High
Category
Privilege Escalation
Content
| # | 关切 | 说明 |
|---|------|------|
| **1** | **名称/能力与实现一致?主凭据是否写进登记?** | **一致**。本 skill 为蝉镜 **数字人视频合成** API 客户端(形象列表、上传、创建/轮询任务、用户明确要求时 **`download_result.py`**)。**`CHANJING_API_BASE` 不是必填**(有默认基址)。**主凭据**为 **`credentials.json`** 内 **`app_id` / `secret_key`** 及刷新后的 **`access_token`**;已在 **`description`**、**`credential_hint`**、**`metadata.openclaw.credentialModel`**、篇首英文摘要、下表 **安全与凭据** 写明。**不**声明 **`primaryEnv`**(双字段文件凭据,与单一 env Key 模型不符)。本 skill **不**将 **`ffmpeg`/`ffprobe`** 写入 `metadata.requires.bins`(与 **一键成片** 不同)。 |
| **2** | **运行时指令范围与敏感数据、任意 URL** | **符合声明目的**。脚本 **读写** **`CHANJING_CONFIG_DIR/credentials.json`**;缺凭证时可能 **浏览器** 或 **`open_login_page.py`**;向 Open API **上传/下载**;用户明确要求落盘时 **`download_result.py`** 会请求 **接口返回的媒体 URL**——请自行判断是否信任 API 主机与链接。若使用 **`create_task.py --callback <URL>`**,蝉镜服务端可能向该 URL **推送任务结果**——仅使用你信任且可接收回调的端点。 |
| **3** | **环境变量适合客户端,主凭据在文件** | **`CHANJING_CONFIG_DIR` / `CHANJING_API_BASE`** 为可选配置。**主凭据非**单一注入式 env Key:**`app_id` / `secret_key`** 经 **guard** 等写入 **`credentials.json`**(路径见 **`metadata.openclaw.credentialModel`**);**`access_token` 持久化到磁盘**,属敏感;勿提交版本库、勿在对话中回显完整密钥。 |
| **4** | **持久化与特权** | 凭据与 token 写入约定 **配置文件**;可能 **交互式登录**。**`always: false`**(默认);**不**修改其它 skill 或全局 Agent 配置。 |
Confidence
91% confidence
Finding
The skill explicitly states it reads and writes credentials.json, may open a browser/login helper, uploads/downloads network content, and can trigger server-side callbacks to arbitrary user-supplied URLs. In combination, this is a sensitive capability set involving secrets, local persistence, and externally directed network flows, which is dangerous without stronger scope restriction and callback validation.

Credential Access

High
Category
Privilege Escalation
Content
| # | 关切 | 说明 |
|---|------|------|
| **1** | **名称/能力与实现一致?主凭据是否写进登记?** | **一致**。本 skill 为蝉镜 **数字人视频合成** API 客户端(形象列表、上传、创建/轮询任务、用户明确要求时 **`download_result.py`**)。**`CHANJING_API_BASE` 不是必填**(有默认基址)。**主凭据**为 **`credentials.json`** 内 **`app_id` / `secret_key`** 及刷新后的 **`access_token`**;已在 **`description`**、**`credential_hint`**、**`metadata.openclaw.credentialModel`**、篇首英文摘要、下表 **安全与凭据** 写明。**不**声明 **`primaryEnv`**(双字段文件凭据,与单一 env Key 模型不符)。本 skill **不**将 **`ffmpeg`/`ffprobe`** 写入 `metadata.requires.bins`(与 **一键成片** 不同)。 |
| **2** | **运行时指令范围与敏感数据、任意 URL** | **符合声明目的**。脚本 **读写** **`CHANJING_CONFIG_DIR/credentials.json`**;缺凭证时可能 **浏览器** 或 **`open_login_page.py`**;向 Open API **上传/下载**;用户明确要求落盘时 **`download_result.py`** 会请求 **接口返回的媒体 URL**——请自行判断是否信任 API 主机与链接。若使用 **`create_task.py --callback <URL>`**,蝉镜服务端可能向该 URL **推送任务结果**——仅使用你信任且可接收回调的端点。 |
| **3** | **环境变量适合客户端,主凭据在文件** | **`CHANJING_CONFIG_DIR` / `CHANJING_API_BASE`** 为可选配置。**主凭据非**单一注入式 env Key:**`app_id` / `secret_key`** 经 **guard** 等写入 **`credentials.json`**(路径见 **`metadata.openclaw.credentialModel`**);**`access_token` 持久化到磁盘**,属敏感;勿提交版本库、勿在对话中回显完整密钥。 |
| **4** | **持久化与特权** | 凭据与 token 写入约定 **配置文件**;可能 **交互式登录**。**`always: false`**(默认);**不**修改其它 skill 或全局 Agent 配置。 |
Confidence
91% confidence
Finding
This line confirms the skill reads/writes the shared credentials file, may launch browser-based login, fetches media from API-returned URLs, and supports callback delivery to a user-provided endpoint. Accepting API-returned download URLs and arbitrary callback URLs broadens the trust boundary and can enable data leakage, SSRF-like interactions, or retrieval from untrusted hosts if not strictly validated by code.

Credential Access

High
Category
Privilege Escalation
Content
|---|------|------|
| **1** | **名称/能力与实现一致?主凭据是否写进登记?** | **一致**。本 skill 为蝉镜 **数字人视频合成** API 客户端(形象列表、上传、创建/轮询任务、用户明确要求时 **`download_result.py`**)。**`CHANJING_API_BASE` 不是必填**(有默认基址)。**主凭据**为 **`credentials.json`** 内 **`app_id` / `secret_key`** 及刷新后的 **`access_token`**;已在 **`description`**、**`credential_hint`**、**`metadata.openclaw.credentialModel`**、篇首英文摘要、下表 **安全与凭据** 写明。**不**声明 **`primaryEnv`**(双字段文件凭据,与单一 env Key 模型不符)。本 skill **不**将 **`ffmpeg`/`ffprobe`** 写入 `metadata.requires.bins`(与 **一键成片** 不同)。 |
| **2** | **运行时指令范围与敏感数据、任意 URL** | **符合声明目的**。脚本 **读写** **`CHANJING_CONFIG_DIR/credentials.json`**;缺凭证时可能 **浏览器** 或 **`open_login_page.py`**;向 Open API **上传/下载**;用户明确要求落盘时 **`download_result.py`** 会请求 **接口返回的媒体 URL**——请自行判断是否信任 API 主机与链接。若使用 **`create_task.py --callback <URL>`**,蝉镜服务端可能向该 URL **推送任务结果**——仅使用你信任且可接收回调的端点。 |
| **3** | **环境变量适合客户端,主凭据在文件** | **`CHANJING_CONFIG_DIR` / `CHANJING_API_BASE`** 为可选配置。**主凭据非**单一注入式 env Key:**`app_id` / `secret_key`** 经 **guard** 等写入 **`credentials.json`**(路径见 **`metadata.openclaw.credentialModel`**);**`access_token` 持久化到磁盘**,属敏感;勿提交版本库、勿在对话中回显完整密钥。 |
| **4** | **持久化与特权** | 凭据与 token 写入约定 **配置文件**;可能 **交互式登录**。**`always: false`**(默认);**不**修改其它 skill 或全局 Agent 配置。 |

### 安全与凭据(登记摘要)
Confidence
86% confidence
Finding
The documentation states that app_id, secret_key, and access_token are persisted in credentials.json and that the token is stored on disk as sensitive cross-skill state. Plaintext persistence of both long-lived credentials and refreshed tokens in a shared file materially increases the impact of local compromise or accidental disclosure.

Credential Access

High
Category
Privilege Escalation
Content
| 维度 | 说明 |
|------|------|
| **主凭据** | `app_id`、`secret_key` 存于 **`credentials.json`**(默认 `~/.chanjing/`,**`CHANJING_CONFIG_DIR`** 可改目录)。经 **`chanjing-credentials-guard`** 配置。非 OpenClaw **`primaryEnv`** 模型(非单一环境变量 API Key)。 |
| **Token** | 脚本将 **`access_token`** / **`expire_in`** 写回同一文件;与 **`chanjing-credentials-guard`** 及其它蝉镜子技能**共用**该文件(磁盘持久化、跨技能状态)。 |
| **回调(可选)** | **`create_task.py --callback`**:若提供,API 可能向用户 URL 发送任务相关负载;属**出站到你方端点**的信任边界,请自行评估。 |
| **环境变量** | **`CHANJING_API_BASE`**、**`CHANJING_CONFIG_DIR`** 可选。 |
Confidence
85% confidence
Finding
This section reiterates that the access token and expiry are written back to a shared credentials file used by multiple skills. Cross-skill shared secret state raises the blast radius of any one skill defect or local read access, because compromise of one component can expose credentials for others.

Credential Access

High
Category
Privilege Escalation
Content
# 鉴权:与 chanjing-credentials-guard 使用同一配置文件(CONFIG_DIR/credentials.json)
# 无 AK/SK 时执行 open_login_page.py 打开注册/登录页
import json
import os
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# 鉴权:与 chanjing-credentials-guard 使用同一配置文件(CONFIG_DIR/credentials.json)
# 无 AK/SK 时执行 open_login_page.py 打开注册/登录页
import json
import os
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# 鉴权:与 chanjing-credentials-guard 使用同一配置文件(CONFIG_DIR/credentials.json)
# 无 AK/SK 时执行 open_login_page.py 打开注册/登录页
import json
import os
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# 鉴权:与 chanjing-credentials-guard 使用同一配置文件(CONFIG_DIR/credentials.json)
# 无 AK/SK 时执行 open_login_page.py 打开注册/登录页
import json
import os
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# 鉴权:与 chanjing-credentials-guard 使用同一配置文件(CONFIG_DIR/credentials.json)
# 无 AK/SK 时执行 open_login_page.py 打开注册/登录页
import json
import os
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# 鉴权:与 chanjing-credentials-guard 使用同一配置文件(CONFIG_DIR/credentials.json)
# 无 AK/SK 时执行 open_login_page.py 打开注册/登录页
import json
import os
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# 鉴权:与 chanjing-credentials-guard 使用同一配置文件(CONFIG_DIR/credentials.json)
# 无 AK/SK 时执行 open_login_page.py 打开注册/登录页
import json
import os
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
# 鉴权:与 chanjing-credentials-guard 使用同一配置文件(CONFIG_DIR/credentials.json)
# 无 AK/SK 时执行 open_login_page.py 打开注册/登录页
import json
import os
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill declares broad capabilities in prose and metadata—reading/writing credentials files, network access, shell invocation, and possible browser launch—but does not constrain them with an explicit tool scope such as permissions or allowed-tools. This creates an overly permissive execution surface where the agent runtime may grant more capability than is necessary, increasing the chance of misuse or prompt-driven abuse.

Session Persistence

Medium
Category
Rogue Agent
Content
---
name: chanjing-video-compose
description: "Use Chanjing video synthesis APIs to create digital human videos from text or audio, with optional background upload, task polling, and explicit download when the user asks to save the result locally. Primary credential: credentials.json (app_id/secret_key; access_token persisted on disk—do not commit; user accepts file-based secrets). Same credentials file as chanjing-credentials-guard. Not OpenClaw primaryEnv. Default path in metadata.openclaw.credentialModel. Optional env: CHANJING_API_BASE, CHANJING_CONFIG_DIR. May invoke open_login_page.py when AK/SK missing. create_task.py optional --callback may cause the API to POST task result payloads to a user-supplied URL. This skill's scripts do not require ffmpeg/ffprobe."
author: chan-skills
binaries: []
env:
Confidence
80% confidence
Finding
The skill explicitly persists access_token state on disk, creating durable session material beyond a single run. Persistent authentication state is not inherently malicious, but it increases the risk of unauthorized reuse if the host is multi-user, compromised, or if the file is mishandled.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The natural-language guidance says that, absent special user requirements, the agent should '默认优先年轻、有活力的形象'. This hard-codes an age/style preference into skill behavior without user opt-in or a documented policy justification, which is a natural-language policy concern.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This is a markdown file, so SQP-2 applies to missing warnings in the skill description. The examples demonstrate uploading local files to a remote service and downloading output to the local machine, but there is no warning about transmitting user content, potential privacy implications, or local file creation.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The reference text states the skill content in Chinese ('本 skill 当前覆盖这些接口') and the examples/defaults consistently assume Chinese-language operation, but there is no indication that the user may choose another language or that the skill is intentionally region-specific. This can violate language/locale policy when a skill imposes a specific language without user opt-in.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
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
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

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

Medium
Category
Data Flow
Content
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)
Confidence
83% confidence
Finding
The credentials file path is derived from CHANJING_CONFIG_DIR, an environment variable, and then written without validation. If an attacker can influence the environment in which this skill runs, they may redirect credential writes to an unintended file location, causing secret leakage or overwriting sensitive files accessible to the current user.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The code sends `app_id` and `secret_key` to a remote API endpoint via HTTP POST, but there is no user-facing warning, log, prompt, or explanatory comment disclosing that local credentials will be transmitted over the network. For code files, network calls that transmit sensitive data should have some visible disclosure unless the warning is documented elsewhere, which is not evident from this file alone.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The natural-language help text sets `--language` default to `cn`, which imposes a specific locale by default. The file does not explain that the skill is intentionally region-specific or ask the user to opt into a Chinese-language default, so this is a language/locale policy concern.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
The script forwards user-provided task content, optional remote media URLs, and an optional callback URL to an external API with no validation or explicit confirmation. In this skill context, that creates a real data-exposure and SSRF-style risk surface: sensitive text may be sent off-platform unexpectedly, and a user-supplied callback can cause the third-party service to POST results to arbitrary destinations, including internal endpoints if the upstream service permits it.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
All user-facing natural-language strings and help text are in Chinese, with no indication that language selection is optional or that the skill is intentionally limited to Chinese-speaking users. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation.

Static analysis

No suspicious patterns detected.