Back to skill

Security audit

Chanjing Customised Person

Security checks for vulnerabilities and agentic risk

Overview

The skill appears purpose-aligned, but it handles API secrets, uploads private videos to dynamic URLs, and can delete remote digital-human resources without enough safety checks.

Install only if you trust the Chanjing API account and this publisher with your source videos and customised-person resources. Use a dedicated low-privilege API credential if possible, keep ~/.chanjing/credentials.json out of version control with owner-only permissions, avoid custom API base URLs unless they are trusted HTTPS endpoints, verify upload/callback destinations, and manually confirm IDs before running deletion commands.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/_auth.py:67
Finding

Credential file is created without restrictive filesystem permissions

Content
View full analysis

Vulnerability Details

File Location: scripts/_auth.py, lines 67-71
Vulnerability Type: Insecure storage of sensitive credentials
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 credential file contains sensitive values including app_id, secret_key, and the persisted access_token. Although the documentation recommends directory mode 0700 and file mode 0600, the implementation does not enforce either restriction.

mkdir() and open() therefore create the directory and file using permissions derived from the process umask. Under a permissive umask, other local users may be able to read the credentials. Rewriting an existing credential file also does not correct insecure pre-existing permissions.

The credential storage path is configurable through environment variables. The write operation additionally performs no check that the destination is a regular file rather than a symbolic link.

Attack Path

  1. The Skill reads a valid app_id and secret_key and determines that its access token must be refreshed.
  2. The refreshed token is passed to write_config().
  3. The function creates or rewrites credentials.json without explicitly setting restrictive permissions.
  4. On a system with permissive file permissions, another local user or process reads the file.
  5. The attacker reuses the application credentials or access token to issue authenticated Chanjing API requests.

Impact Assessment

Successful exploitation exposes Chanjing API credentials to another local security principal. The attacker may obtain the same API privileges as the victim account, including inspecting digital-human resources, creating jobs, uploading content, and deleting digital-human records wh ...[truncated 226 chars]

Remediation
View remediation

Remediation Suggestions

  • Create the credential directory with mode 0700 and explicitly enforce that mode on existing directories.
  • Create credential files with mode 0600, independent of the process umask.
  • Write updates to a securely created temporary file in the same directory, flush and synchronize it, set mode 0600, and atomically replace the destination.
  • Reject symbolic links and verify that the destination is a regular file owned by the expected user before reading or replacing it.
  • Correct insecure permissions on existing credential files before storing refreshed tokens.
  • Avoid printing credential values or access tokens in error output and ensure credentials.json remains excluded from version control.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/_auth.py:20
Finding

Unvalidated API base URL can receive application secrets and access tokens

Content
View full analysis

Vulnerability Details

File Location: scripts/_auth.py, lines 20-26 and 93-101
Vulnerability Type: Unvalidated destination for sensitive network requests
Risk Level: Medium

Vulnerable Code

python
def openapi_base_url() -> str:
    return (
        os.environ.get("CHANJING_OPENAPI_BASE_URL")
        or os.environ.get("CHANJING_API_BASE")
        or _DEFAULT_OPENAPI_BASE
    ).rstrip("/")
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:

Technical Analysis

The API base URL can be replaced through CHANJING_OPENAPI_BASE_URL or the legacy CHANJING_API_BASE variable. The value is used without verifying its scheme, host, port, user-information component, or relationship to the expected Chanjing service.

During token acquisition, the Skill sends app_id and secret_key to this destination. Other scripts use the same configurable base and attach the resulting access_token header to their requests. Because HTTPS is not enforced, a value using plaintext HTTP is accepted despite the manifest describing HTTPS outbound communication.

A custom API endpoint may be useful for legitimate testing, but transmitting production credentials to an arbitrary environment-controlled URL exceeds a safe default trust boundary unless the destination is validated and explicitly approved.

Attack Path

  1. An attacker or compromised launcher influences CHANJING_OPENAPI_BASE_URL or CHANJING_API_BASE before the Skill starts.
  2. The variable is set to an attacker-controlled URL, including a plaintext HTTP endpoint.
  3. The Skill loads app_id and secret_key from the local credential file.
  4. _auth.py sends those values to ...[truncated 779 chars]
Remediation
View remediation

Remediation Suggestions

  • Parse the configured base URL before use and require the https scheme.
  • Reject malformed hosts, URL user information, fragments, unexpected paths, and unsupported ports.
  • Use https://open-api.chanjing.cc as the locked-down production default.
  • If custom hosts are required, require explicit user approval and validate them against a trusted allowlist.
  • Keep test credentials separate from production credentials when custom API environments are enabled.
  • Prevent authenticated requests from following redirects to a different origin.
  • Centralize URL validation and API request construction so every script applies the same policy.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/upload_file.py:92
Finding

API-provided upload URL is used without enforcing HTTPS or validating its destination

Content
View full analysis

Vulnerability Details

File Location: scripts/upload_file.py, lines 92-109
Vulnerability Type: Unvalidated destination for sensitive file upload
Risk Level: Medium

Vulnerable Code

python
sign_url = payload.get("sign_url")
mime_type = payload.get("mime_type", "application/octet-stream")
file_id = payload.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

Dynamic upload hosts are necessary because Chanjing may return a signed object-storage or CDN URL on a host different from the API host. However, the implementation trusts the complete sign_url without validating its scheme or destination.

In particular, it does not enforce HTTPS, reject URL user information, or restrict redirects. Consequently, a compromised or misconfigured API endpoint can return an HTTP or attacker-controlled URL, and the Skill will upload the entire user-selected source video to it.

The access token is not attached to the PUT request, which limits credential exposure in this specific flow. Nevertheless, the local video is sensitive user content, and plaintext or unintended upload destinations violate the documented HTTPS boundary.

Attack Path

  1. The configured API is compromised, malicious, or impersonated through the separately configurable API base.
  2. The create_upload_url response supplies an attacker-controlled or plaintext sign_url.
  3. upload_file.py verifies only that the value is non-empty.
  4. The script reads the complete user-selected video from disk.
  5. It performs an HTTP PUT to the supplied destination.
  6. The attacker receives the p ...[truncated 585 chars]
Remediation
View remediation

Remediation Suggestions

  • Parse sign_url and require the https scheme before opening the local file.
  • Reject malformed URLs, user-information components, fragments, and missing hostnames.
  • Disable redirects for the upload request or allow them only when the destination remains HTTPS and satisfies the same host policy.
  • Where the provider can document stable storage domains, validate the hostname against provider-controlled suffixes.
  • If stable domains are impossible, require explicit approval before uploading to an unfamiliar host and display only a sanitized destination without signed query parameters.
  • Obtain and validate the upload URL before reading the complete file into memory.
  • Consider streaming the upload rather than loading the entire file into memory, particularly for large videos.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (43)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The declared description says the skill manages custom digital humans themselves: create, inspect, list, poll, and delete them from uploaded source videos. But the supplied code chunk does not operate on digital human resources at all. It interacts with common file upload endpoints, uploads a local file to a signed storage URL, polls file processing readiness, and returns a file_id. While this may be a supporting step for a larger custom-digital-human workflow, the actual code here materially differs from the declared primary purpose because it only handles file ingestion/preparation and lacks the stated person creation, inspection, listing, polling of person jobs, or deletion behavior.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
89% confidence
Finding

The skill explicitly accesses a local credentials.json containing app_id, secret_key, and persisted access tokens. Any skill that reads and rewrites long-lived credentials is security-sensitive because compromise of the skill, logs, or filesystem permissions could expose API secrets and enable unauthorized API actions.

Content

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

md
description: >-
  Use Chanjing customised person APIs to create, inspect, list, poll, and
  delete custom digital humans from uploaded source videos.
credential: credentials.json (app_id/secret_key; access_token and expire_in persisted on disk; same file as chanjing-credentials-guard)
openclaw_primary_env: false
environment: CHANJING_OPENAPI_CREDENTIALS_DIR, CHANJING_OPENAPI_BASE_URL
legacy_environment: CHANJING_CONFIG_DIR, CHANJING_API_BASE

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

The notes disclose two risky behaviors: automatic browser opening when credentials are missing and uploading file contents to an API-returned sign_url whose host may differ from the primary API domain. Combined with optional callback handling of sensitive payloads, this expands the trust boundary and creates opportunities for credential misuse, data exfiltration, or user confusion if destinations are not tightly validated.

Content

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

md
requires_ffmpeg: false
requires_ffprobe: false
notes: >-
  Reads ~/.chanjing/credentials.json; may open browser if AK/SK missing.
  Upload path: GET create_upload_url then HTTPS PUT to API-returned sign_url
  (host may differ from open-api). Optional --callback URL may receive sensitive
  POST payloads from Chanjing.

Credential Access

High
Category
Privilege Escalation
Confidence
87% confidence
Finding

Sharing ~/.chanjing/credentials.json with another skill increases blast radius: a compromise or misuse in either skill can expose the same credentials and tokens. Automatic browser opening on missing credentials also introduces an external interaction path that can surprise users in automated or privileged environments.

Content

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

md
本 Skill 与 guard 共用:

* `~/.chanjing/credentials.json`
* `https://open-api.chanjing.cc`

无凭证时,脚本会自动打开蝉镜登录页,并提示配置命令。

Credential Access

High
Category
Privilege Escalation
Confidence
97% confidence
Finding

This section confirms persistent local credential storage, token write-back, open network mode, uploads to API-supplied sign_url hosts outside a fixed whitelist, and optional callbacks that may transmit sensitive task payloads to arbitrary URLs. In context, these are real security concerns because the skill handles local files and secrets while allowing outbound communication beyond a tightly bounded API perimeter.

Content

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

md
与 **Purpose / Credentials / Persistence / Network** 相关的逐项说明见 **`manifest.yaml`**(含 **`permissions.network_mode: open`** 与 **`signUrlPutNote`**)。以下仅 **SKILL 正文补充**:

- **`credentials.json`**:脚本会读取本地凭据;刷新后的 **`access_token` / `expire_in` 写回同一文件**为**预期行为**。须限制目录/文件权限(如目录 `0700`、文件 `0600`),并**确保永不提交版本库**(见 manifest **`doNotCommitToVcs`**)。
- **`sign_url` 与 PUT 主机**:`upload_file.py` / `get_upload_url.py` 先请求 `open-api.chanjing.cc` 的 `create_upload_url`,再向响应中的 **`sign_url` 发起 HTTPS PUT**;该 URL 的主机常为蝉镜侧对象存储或 CDN,**可能不在**固定主机白名单中,清单中已改为 **`network_mode: open`** 以如实声明。
- **`create_person.py --callback`**:若传入 URL,远程服务可能向该端点 **POST** 任务结果,载荷可能含状态与资源引用等**敏感信息**;须自行信任该端点并承担出站与数据暴露风险。
- **本地视频**:仅按用户给出的路径读取视频字节并上传到 API 指定端点;不扫描其它无关系统路径。

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

Persisting access tokens on disk increases the exposure window if the workstation, workspace, or home directory is compromised, backed up insecurely, or accidentally shared. Although this is documented and appears operational rather than malicious, storing refreshed access_token and expiry data locally creates a real credential-management risk.

Content

Scanner excerpt · manifest.yaml (reported line 69)May include surrounding context.

yaml
persistAccessTokenOnDisk: true
  primaryEnvIntentionallyOmitted: true
  doNotCommitToVcs:
    - credentials.json
  persistNote: >-
    access_token 与 expire_in 刷新后写回 credentials.json 为预期行为;须限制文件权限(如 0600/目录 0700)
    并确保永不提交版本库。

Credential Access

High
Category
Privilege Escalation
Confidence
84% confidence
Finding

The persistNote explicitly normalizes writing refreshed tokens back into credentials.json, which confirms that live authentication material is stored on disk. This is not malicious, but it increases the chance of credential leakage through misconfigured permissions, developer backups, dotfile syncing, or accidental inclusion in archives.

Content

Scanner excerpt · manifest.yaml (reported line 71)May include surrounding context.

yaml
doNotCommitToVcs:
    - credentials.json
  persistNote: >-
    access_token 与 expire_in 刷新后写回 credentials.json 为预期行为;须限制文件权限(如 0600/目录 0700)
    并确保永不提交版本库。

clientPermissions:

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Granting write access to the credentials.json path means the skill can modify stored authentication material, which can be risky if the skill is compromised or behaves unexpectedly. In this manifest, the write is justified by token refresh behavior, so the risk is contextual rather than overtly malicious, but it still expands the blast radius of any bug or abuse.

Content

Scanner excerpt · manifest.yaml (reported line 91)May include surrounding context.

yaml
- "${CHANJING_OPENAPI_CREDENTIALS_DIR or CHANJING_CONFIG_DIR or ~/.chanjing}/credentials.json"
      - user_provided_video_paths
    write:
      - "${CHANJING_OPENAPI_CREDENTIALS_DIR or CHANJING_CONFIG_DIR or ~/.chanjing}/credentials.json"
  browser:
    mayOpenForAuth: true
    documentedHosts:

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 · manifest.yaml (reported line 51)May include surrounding context.

yaml
#!/usr/bin/env python3
# 鉴权:与 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 · manifest.yaml (reported line 58)May include surrounding context.

yaml
#!/usr/bin/env python3
# 鉴权:与 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 · manifest.yaml (reported line 60)May include surrounding context.

yaml
#!/usr/bin/env python3
# 鉴权:与 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 · manifest.yaml (reported line 88)May include surrounding context.

yaml
#!/usr/bin/env python3
# 鉴权:与 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 2)May include surrounding context.

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

Credential Access

High
Category
Privilege Escalation
Confidence
93% confidence
Finding

Defining and using a predictable plaintext credentials file for app_id, secret_key, and token creates a local credential exposure point. In the context of an auth helper, this is more dangerous because the file is central to accessing the external service, so compromise of the file directly enables unauthorized API use.

Content

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

python
CONFIG_DIR = credentials_config_dir()
CONFIG_FILE = CONFIG_DIR / "credentials.json"
API_BASE = openapi_base_url()
BUFFER_SECONDS = 300
LOGIN_URL = "https://www.chanjing.cc/openapi/login"

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill text indicates meaningful capabilities including reading environment variables, reading and writing credential files, network access, and shell-based script execution, yet the skill file itself does not declare a tool scope. That weakens policy enforcement and review because an agent may be granted broader runtime powers than users or reviewers expect.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The trigger phrases are broad and do not define clear preconditions such as required user authorization, ownership of the uploaded media, or confirmation gates for lifecycle actions. In an agent setting, vague activation boundaries can cause the skill to trigger on loosely related requests and perform sensitive API operations like creation, listing, polling, or deletion without sufficient user intent validation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The examples include a direct delete command for a custom digital human without any warning, confirmation step, or mention of irreversibility. In a skill that manages remote resources, this increases the chance of accidental or socially engineered destructive actions, especially if an agent follows examples as normative behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The documentation is written entirely in Chinese, including operational guidance and safety-relevant notes, with no indication that the skill supports other languages or that Chinese is a required, justified locale. This creates a natural-language policy concern because it effectively imposes a language choice on users without opt-in.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The markdown describes the delete_customised_person endpoint and request body, but it does not include any caution that this action deletes a customised person and may be irreversible or affect user data. For markdown files, destructive behaviors should be clearly disclosed so users understand the impact before invoking the skill.

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

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script stores app_id, secret_key, and access token in a local JSON file under the user's home/config directory without applying restrictive file permissions or using a secure secret store. If another local user, malware, or an over-permissive backup/sync process can read that file, the credentials can be stolen and reused to access the API.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The function sends app_id and secret_key in an HTTP POST request to obtain an access token. While the network call is part of authentication, this file provides no visible confirmation prompt, print/log disclosure, or explanatory comment warning the user that locally stored credentials will be transmitted to a remote service.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module docstring and CLI usage/help context are written in Chinese, which imposes a specific language on users without offering an explicit language choice for the interface. The stated policy flags language or locale constraints unless the skill offers opt-in or clearly documents a justified region-specific limitation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This script performs an irreversible delete operation immediately after receiving an --id, with no confirmation prompt, dry-run mode, or secondary validation. In the context of a skill that manages remote digital-human assets over an authenticated API, this increases the chance of accidental or automated deletion of production resources if the wrong ID is supplied or the command is triggered unintentionally.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

All user-facing natural-language text in the module docstring and CLI descriptions is presented only in Chinese, with no indication that another language is available. Under the language/locale policy, forcing a specific language without user opt-in can be a policy violation unless the locale restriction is clearly documented and justified.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.