Back to skill

Security audit

Chanjing Avatar

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it claims, but its credential-bearing network destination is too easy to redirect through environment variables, so users should review it before installing.

Install only if you trust this publisher and will run it in a controlled environment. Before use, avoid setting CHANJING_OPENAPI_BASE_URL or CHANJING_API_BASE to anything other than the legitimate Chanjing API, protect ~/.chanjing/credentials.json with owner-only permissions, and treat any uploaded video/audio/text as leaving your machine for Chanjing processing.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/_auth.py:18
Finding

Environment-Controlled API Base URL Can Redirect Credentials and Access Tokens

Content
View full analysis
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: body = json.loads(resp.read().decode("utf-8")) except Exception as e: return None, str(e) ``` The remaining scripts similarly construct requests from the environment-controlled `API_BASE` and attach the access token: ```python url = f"{API_BASE}/open/v1/video_lip_sync/create" req = urllib.request.Request( url, data=json.dumps(body).encode("utf-8"), headers={"access_token": token, "Content-Type": "application/json"}, method="POST", ) ``` ### Technical Analysis The API base URL can be replaced through either `CHANJING_OPENAPI_BASE_URL` or the legacy `CHANJING_API_BASE` variable. The code applies only `rstrip("/")`; it does not require HTTPS or verify that the destination hostname is `open-api.chanjing.cc`. When the cached token is absent or close to expiration, `_auth.py` sends the long-lived `app_id` and `secret_key` to the configured endpoint. The other scripts attach the access token to requests sent through the same configurable base URL. This behavior conflicts with the intended network allowlist in `manifest.yaml`, which documents Chanjing hosts rather than arbitrary ...[truncated 1229 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/upload_file.py:82
Finding

Local Media Is Uploaded to an Unvalidated API-Supplied URL

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/_auth.py:62
Finding

Credential File Is Written Without Enforced Owner-Only Permissions

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
scripts/_auth.py:34
Finding

Missing Credentials Trigger Unverified Execution of a Sibling Skill Script

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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (32)

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

This skill is designed to access application credentials and use them to obtain bearer tokens for a third-party API. Credential access is necessary for function, but it is still security-sensitive because compromise, oversharing, or misuse of the credential file could allow unauthorized API actions and access to generated media workflows.

Content

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

md
description: >-
  Use Chanjing Avatar API for lip-syncing video generation (upload audio/video,
  create tasks, poll results).
credential: credentials.json (app_id/secret_key; access_token persisted on disk)
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
90% confidence
Finding

The instructions explicitly direct reading app_id and secret_key from a local file to exchange for an access token. Although this is expected behavior for the API client, it creates a high-value secret handling path that becomes dangerous if combined with excessive tool access, logging, or unclear trust boundaries.

Content

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

Obtain AccessToken

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

http
POST /open/v1/access_token

Credential Access

High
Category
Privilege Escalation
Confidence
87% confidence
Finding

The sample request body shows direct inclusion of app_id and secret_key sourced from credentials.json, reinforcing that the skill processes raw long-lived credentials. If operators or agents mirror this pattern insecurely, those secrets may end up in logs, traces, shell history, or error output.

Content

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

json
{
  "app_id": "<从 credentials.json 读取>",
  "secret_key": "<从 credentials.json 读取>"
}

Credential Access

High
Category
Privilege Escalation
Confidence
87% confidence
Finding

This line continues the example showing raw secret material being consumed from local storage, which is a legitimate but sensitive operation. In the context of a skill that also performs network operations, the combination raises the risk of accidental secret disclosure or credential misuse if the implementation is not tightly constrained.

Content

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

json
{
  "app_id": "<从 credentials.json 读取>",
  "secret_key": "<从 credentials.json 读取>"
}

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

The scripts share a common credential file to obtain tokens, meaning multiple entry points in the skill can touch sensitive authentication material. This broadens the attack surface because any script invocation, wrapper, or debugging path may inadvertently expose or misuse credentials if not carefully controlled.

Content

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

md
## Scripts

本 Skill 提供脚本(`skills/chanjing-avatar/scripts/`),与 **chanjing-credentials-guard** 使用同一配置文件(`~/.chanjing/credentials.json`)获取 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 · manifest.yaml (reported line 48)May include surrounding context.

yaml
variables:
    - name: CHANJING_OPENAPI_CREDENTIALS_DIR
      required: false
      description: 存放 credentials.json 的目录(兼容 CHANJING_CONFIG_DIR),默认 ~/.chanjing
    - name: CHANJING_OPENAPI_BASE_URL
      required: false
      description: Open API 基址(兼容 CHANJING_API_BASE),默认 https://open-api.chanjing.cc

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 55)May include surrounding context.

yaml
variables:
    - name: CHANJING_OPENAPI_CREDENTIALS_DIR
      required: false
      description: 存放 credentials.json 的目录(兼容 CHANJING_CONFIG_DIR),默认 ~/.chanjing
    - name: CHANJING_OPENAPI_BASE_URL
      required: false
      description: Open API 基址(兼容 CHANJING_API_BASE),默认 https://open-api.chanjing.cc

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 57)May include surrounding context.

yaml
variables:
    - name: CHANJING_OPENAPI_CREDENTIALS_DIR
      required: false
      description: 存放 credentials.json 的目录(兼容 CHANJING_CONFIG_DIR),默认 ~/.chanjing
    - name: CHANJING_OPENAPI_BASE_URL
      required: false
      description: Open API 基址(兼容 CHANJING_API_BASE),默认 https://open-api.chanjing.cc

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 75)May include surrounding context.

yaml
variables:
    - name: CHANJING_OPENAPI_CREDENTIALS_DIR
      required: false
      description: 存放 credentials.json 的目录(兼容 CHANJING_CONFIG_DIR),默认 ~/.chanjing
    - name: CHANJING_OPENAPI_BASE_URL
      required: false
      description: Open API 基址(兼容 CHANJING_API_BASE),默认 https://open-api.chanjing.cc

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 78)May include surrounding context.

yaml
variables:
    - name: CHANJING_OPENAPI_CREDENTIALS_DIR
      required: false
      description: 存放 credentials.json 的目录(兼容 CHANJING_CONFIG_DIR),默认 ~/.chanjing
    - name: CHANJING_OPENAPI_BASE_URL
      required: false
      description: Open API 基址(兼容 CHANJING_API_BASE),默认 https://open-api.chanjing.cc

Credential Access

High
Category
Privilege Escalation
Confidence
89% confidence
Finding

Persisting the access token on disk increases the exposure window for credential theft from the local filesystem, backups, or other processes with read access to the credentials directory. In this skill's context, disk persistence is not inherently malicious, but storing bearer-style tokens at rest creates avoidable risk if filesystem protections are weak or the host is shared.

Content

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

yaml
persistAccessTokenOnDisk: true
  primaryEnvIntentionallyOmitted: true
  doNotCommitToVcs:
    - credentials.json

clientPermissions:
  network:

Credential Access

High
Category
Privilege Escalation
Confidence
93% confidence
Finding

This file is designed to read and persist API credentials from a shared credentials.json file, including app_id, secret_key, and access tokens. Storing long-lived secrets in plaintext under a predictable location increases the risk of credential theft by other local processes, users, backups, or accidental disclosure.

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
95% confidence
Finding

The explicit use of a predictable credentials.json path under a configurable directory centralizes sensitive secrets in a plaintext file that other software may discover and read. Because this authentication helper also updates and reuses the stored access token, compromise of that file can directly enable unauthorized API access.

Content

Scanner excerpt · scripts/_auth.py (reported line 28)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
90% confidence
Finding

The skill clearly describes capabilities that require filesystem, environment, shell, and network access, yet the file itself does not present explicit tool-scope restrictions or a visible least-privilege declaration. In a skill that reads credentials, uploads local media, and polls remote APIs, missing scope boundaries increase the chance of over-broad execution and unintended data exposure.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
86% confidence
Finding

The metadata states that the access token is persisted on disk, creating session persistence beyond the immediate task. Persisted bearer tokens increase exposure on shared systems and can allow replay or unauthorized API use if local files are copied, backed up insecurely, or read by other processes.

Content

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

md
name: chanjing-avatar
description: >-
  Use Chanjing Avatar API for lip-syncing video generation (upload audio/video,
  create tasks, poll results).
credential: credentials.json (app_id/secret_key; access_token persisted on disk)
openclaw_primary_env: false
environment: CHANJING_OPENAPI_CREDENTIALS_DIR, CHANJING_OPENAPI_BASE_URL

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill declares use of a local credentials file and persistence of access tokens on disk without a prominent user-facing warning about secret handling, storage location, and security implications. Persisted tokens can be reused if the host is shared or compromised, especially when the storage protections and lifecycle are not explained.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill instructs the agent to upload local video/audio files and use credential-derived tokens with an external API, but it does not provide a clear user-facing warning that local media and associated metadata will leave the local environment. This can lead to unintentional disclosure of sensitive personal, biometric, or proprietary content.

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

This code writes credentials and tokens to a local JSON file and also invokes another script via subprocess to open a login page. While comments/docstrings describe the behavior for developers, there is no user-facing warning, confirmation, or visible notice at the point of the file write or subprocess launch, which matches the missing-warning criterion for code files.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The function sends app_id and secret_key to a remote API endpoint to obtain an access token. Although this is likely part of the authentication purpose, the file itself provides no user-facing warning or visible disclosure that sensitive credentials will be transmitted over the network.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The script transmits user-supplied text/audio metadata and an optional callback URL to a remote API without any validation, warning, or restriction. In skill/agent contexts, this can enable silent exfiltration of sensitive content to third-party infrastructure and can also permit dangerous callback destinations such as internal or attacker-controlled endpoints.

Content

No source excerpt is available for this finding.

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · scripts/create_task.py (reported line 18)May include surrounding context.

python
sys.path.insert(0, str(Path(__file__).resolve().parent))
from _auth import get_token

API_BASE = (__import__("os").environ.get("CHANJING_OPENAPI_BASE_URL") or __import__("os").environ.get("CHANJING_API_BASE") or "https://open-api.chanjing.cc").rstrip("/")


def main():

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · scripts/get_upload_url.py (reported line 18)May include surrounding context.

python
sys.path.insert(0, str(Path(__file__).resolve().parent))
from _auth import get_token

API_BASE = (__import__("os").environ.get("CHANJING_OPENAPI_BASE_URL") or __import__("os").environ.get("CHANJING_API_BASE") or "https://open-api.chanjing.cc").rstrip("/")


def main():

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · scripts/poll_task.py (reported line 19)May include surrounding context.

python
sys.path.insert(0, str(Path(__file__).resolve().parent))
from _auth import get_token

API_BASE = (__import__("os").environ.get("CHANJING_OPENAPI_BASE_URL") or __import__("os").environ.get("CHANJING_API_BASE") or "https://open-api.chanjing.cc").rstrip("/")


def main():

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · scripts/upload_file.py (reported line 19)May include surrounding context.

python
sys.path.insert(0, str(Path(__file__).resolve().parent))
from _auth import get_token

API_BASE = (__import__("os").environ.get("CHANJING_OPENAPI_BASE_URL") or __import__("os").environ.get("CHANJING_API_BASE") or "https://open-api.chanjing.cc").rstrip("/")


def main():

Static analysis

No suspicious patterns detected.