Back to skill

Security audit

video-creation

Security checks for vulnerabilities and agentic risk

Overview

The skill largely matches its video-generation purpose, but it needs review because it trusts remote media URLs without strong bounds and hardcodes demographic/cultural defaults into generated outputs.

Install only if you are comfortable sending scripts, generated audio, and video prompts to Chanjing and running ffmpeg locally. Use a dedicated output directory, avoid sensitive input media, run in a contained environment if possible, and review or override the demographic/cultural defaults before using it for general-purpose content.

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

Warning
Location
scripts/run_render.py:165
Finding

Unrestricted Retrieval of API-Supplied Media URLs Enables SSRF

Content
View full analysis

Vulnerability Details

File Location: scripts/run_render.py:165-169; related URL propagation occurs in clients/avatar_client.py:706-712 and clients/ai_creation_client.py:184-190
Vulnerability Type: Server-Side Request Forgery through unvalidated media URLs
Risk Level: Medium

Vulnerable Code

python
def download_url(url: str, dest: Path) -> None:
    with DOWNLOAD_SEM:
        req = urllib.request.Request(url, method="GET")
        with urllib.request.urlopen(req, timeout=300) as resp:
            dest.write_bytes(resp.read())

The downloaded URL is obtained directly from API task results:

python
def poll_video_task_url(video_id: str, interval: int = 10, timeout: int = 1800) -> str:
    data = poll_video_task(video_id, interval=interval, timeout=timeout)
    video_url = data.get("video_url")
    if not video_url:
        raise RuntimeError("Task succeeded but returned no video_url")
    return str(video_url)
python
def poll_ai_creation_task_url(
    unique_id: str,
    *,
    interval: int = 10,
    timeout: int = 1800,
) -> str:
    data = poll_ai_creation_task(unique_id, interval=interval, timeout=timeout)
    url = first_output_url(data)
    if not url:
        raise RuntimeError("Task succeeded but returned no output_url")
    return url

Technical Analysis

The renderer passes URLs from remote API responses directly to urllib.request.urlopen() without validating:

  • The URL scheme
  • The destination hostname and port
  • The resolved IP address
  • Redirect destinations
  • Whether the destination is an approved Chanjing media host or CDN
  • Whether the response is an expected media type

Although these URLs normally originate from the declared Chanjing API, the client treats the API response as fully trusted. A compromised API account, upstream service, DNS path, or maliciously altered task response could make the Agent issue req ...[truncated 1567 chars]

Remediation
View remediation

Remediation Suggestions

  1. Accept only https URLs for generated-media downloads.
  2. Maintain an explicit allowlist of approved Chanjing media and CDN hostnames.
  3. Resolve the hostname before connecting and reject loopback, private, link-local, multicast, unspecified, and reserved addresses.
  4. Disable automatic redirects or validate the scheme, hostname, port, and resolved address again after every redirect.
  5. Reject URLs containing embedded credentials or unexpected ports.
  6. Validate the response Content-Type against an allowlist of expected audio and video types.
  7. Centralize all media retrieval in one hardened downloader so download_url(), download_video(), and download_ai_creation_result() enforce identical controls.
  8. Run media parsing in a sandbox with restricted network access, filesystem access, CPU, and memory.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/run_render.py:165
Finding

Unbounded Network Transfers Permit Memory and Disk Exhaustion

Content
View full analysis

Vulnerability Details

File Location: scripts/run_render.py:165-169; related implementations occur in clients/avatar_client.py:744-755,821-833 and clients/ai_creation_client.py:210-226
Vulnerability Type: Unbounded buffering of remote and local media content
Risk Level: Medium

Vulnerable Code

python
def download_url(url: str, dest: Path) -> None:
    with DOWNLOAD_SEM:
        req = urllib.request.Request(url, method="GET")
        with urllib.request.urlopen(req, timeout=300) as resp:
            dest.write_bytes(resp.read())

The avatar upload path also reads the complete local file into memory before sending it:

python
def upload_to_oss(sign_url: str, file_path: Path, mime_type: str) -> None:
    with open(file_path, "rb") as f:
        content = f.read()

    req = urllib.request.Request(
        sign_url,
        data=content,
        headers={"Content-Type": mime_type},
        method="PUT",
    )

    with urllib.request.urlopen(req, timeout=120) as resp:
        if resp.status not in (200, 204):
            raise RuntimeError(f"Upload failed with status={resp.status}")

The other download helpers use the same full-response buffering pattern:

python
with urllib.request.urlopen(req, timeout=120) as resp:
    with open(output, "wb") as handle:
        handle.write(resp.read())

Technical Analysis

The download functions call resp.read() with no maximum byte count and buffer the entire response before writing it. The upload implementation similarly loads the complete source file into one in-memory byte string.

Network timeouts limit elapsed waiting periods but do not impose response-size limits. The download semaphore restricts concurrency to two transfers, but each transfer can still consume an unbounded amount of memory and disk space.

No controls were found for:

  • Maximum response size
  • Maximum source-file size
  • Cumulat ...[truncated 1416 chars]
Remediation
View remediation

Remediation Suggestions

  1. Stream downloads and uploads in fixed-size chunks rather than using unbounded read().
  2. Define separate maximum sizes for TTS audio, digital-human videos, and AI-generated videos.
  3. Reject a response before downloading when its declared Content-Length exceeds the applicable limit.
  4. Track actual bytes received because Content-Length may be absent or dishonest, and abort immediately when the configured limit is exceeded.
  5. Write downloads to a temporary file and atomically rename it only after validation succeeds.
  6. Delete partial files when a transfer fails or exceeds its limit.
  7. Enforce a cumulative quota for the rendering work directory and verify available disk space before starting each transfer.
  8. Apply process-level memory, disk, CPU, and execution-time limits where the Skill is run in a multi-tenant or automated Agent environment.
  9. Validate downloaded files with strict media-type and container checks before passing them to ffprobe or ffmpeg.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (42)

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · clients/auth.py (reported line 45)May include surrounding context.

python
)

    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            res = json.loads(resp.read().decode("utf-8"))
    except Exception as e:
        return None, None, f"获取 access_token 失败: {e}"

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding

声明描述的是一个“输入选题或口播稿,一键生成完整短视频成片”的综合型技能,核心能力应覆盖脚本生成、分镜、数字人口播、AI画面拼接等完整流水线。实际代码块只展示了对 chanjing AI creation 接口的通用封装,特别是 creation_type=4 的视频生成任务提交、状态轮询和结果下载。虽然这与声明中的“AI 文生视频调用能力”一致,但远不足以支持“完整成片”这一主要承诺。未发现与描述无关的高风险越权行为;不匹配主要体现在声明显著夸大了已实现能力范围。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

从代码内容看,tts_client.py 只调用了与音频合成相关的 API(create_audio_task、audio_task_state、list_common_audio),其核心功能是文本转语音和查询音色。这与声明中的一部分“TTS能力”一致,但不足以支撑“自动生成完整短视频成片”的整体描述。当前代码块没有展示任何视频生成、数字人驱动、镜头编排、文案策划或混剪逻辑,因此若将该代码块作为该 skill 的实际实现代表,则描述明显比实际行为宽泛得多,存在能力夸大型不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

声明描述的是一个面向终端用户的一键短视频生成 skill,核心能力应包括内容生成、分镜规划、TTS 合成、数字人视频生成和 AI 视频混剪。而实际提供的代码仅是 tests/test_id_resolver.py 测试文件,作用是为测试解析/获取 audio_man、person_id、figure_type 等标识符。虽然它间接接触了 TTS 与数字人相关客户端,但只是列出可用音色和公共数字人 ID,未执行视频生成、文案生成、分镜生成或完整渲染流程。因此该代码块的实际行为与声明用途存在明显且实质性的偏差。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
87% confidence
Finding

声明描述的是一个面向终端用户的完整短视频自动生成 skill,核心能力应包括根据主题/稿件生成内容并调用 TTS、数字人和 AI 视频服务完成成片。但本代码片段仅是测试文件,功能集中在校验 run_render 相关辅助逻辑和示例工作流输入格式,外加通过 test_id_resolver 填充测试 ID。虽然测试中能看出底层系统可能涉及 TTS、数字人和 AI 视频参数,但该片段本身并未执行这些核心业务能力,而是验证辅助函数与测试配置。因此,就“所提供代码片段实际做什么”而言,与声明的主要用途存在明显不一致。

Content

No source excerpt is available for this finding.

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/run_render.py (reported line 145)May include surrounding context.

python
capture_output=True,
        text=True,
        timeout=timeout,
        env={**os.environ, **(env or {})},
    )
    if r.returncode != 0:
        msg = (r.stderr or r.stdout or "").strip() or f"exit {r.returncode}"

Natural-Language Policy Violations

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

Mandating East Asian ethnicity and specific English phrasing by default, without user opt-in, introduces a demographic and locale policy override at the prompt-template level. Because this skill auto-generates finished video assets, the bias is operationalized across outputs at scale, making discriminatory or misleading representation more likely and harder for users to notice or correct.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The historical section defaults unspecified narratives toward a China-centric setting, effectively forcing a particular civilization and locale into ambiguous content. In a general-purpose video creation skill, this can distort educational, documentary, or creative outputs and propagate culturally inaccurate or exclusionary defaults without consent.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The reasoning-order section reinforces that ambiguous cases should inherit a China-context default, which institutionalizes regional bias in the agent's decision process. This is dangerous because it affects not just wording but downstream visual generation choices, leading to repeated non-consensual cultural framing across many generated videos.

Content

No source excerpt is available for this finding.

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 · tests/test_id_resolver.py (reported line 130)May include surrounding context.

python
except Exception as e:
            self.skipTest(
                "无法自动解析测试 ID(可复制 tests/chanjing_test_defaults.example.json 为 "
                f"chanjing_test_defaults.json 填写 ID,或配置 ~/.chanjing/credentials.json):{e}"
            )
        payload["audio_man"] = ids["audio_man"]
        payload["person_id"] = ids["person_id"]

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 · tests/test_run_render_stub.py (reported line 119)May include surrounding context.

python
except Exception as e:
            self.skipTest(
                "无法自动解析测试 ID(可复制 tests/chanjing_test_defaults.example.json 为 "
                f"chanjing_test_defaults.json 填写 ID,或配置 ~/.chanjing/credentials.json):{e}"
            )
        payload["audio_man"] = ids["audio_man"]
        payload["person_id"] = ids["person_id"]

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill declares broad capabilities including environment-variable access, local file read/write, network calls, and shell execution via ffmpeg/ffprobe, but does not define any explicit tool scope or permission boundary. In an agent setting, undocumented powerful capabilities increase the risk of over-privileged execution, unexpected data access, and abuse through prompt-driven workflows.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The documentation imposes a default preference for 'young/energetic' avatars without user consent, which creates an undocumented automated profiling and persona-selection policy. In a content-generation system, this can produce biased or inappropriate outputs, undermine user intent, and create fairness/compliance risk, especially when the agent is instructed to infer demographics from topic or semantics.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

Repeating a default policy favoring 'young' digital humans operationalizes a demographic bias in the skill's input guidance. Because the system may autonomously choose presenters, this can systematically steer outputs toward age-coded personas without transparency or user approval, raising safety, fairness, and reputational concerns.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

This code sends JSON payloads to a remote API using POST, and the payload can include user-provided prompt content and related generation parameters. There is no confirmation prompt, visible logging, or explanatory comment/docstring warning that user data will be transmitted to an external service.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This function retrieves content from a URL and writes it to a local file path, creating parent directories if needed. The code contains no confirmation, visible notice, or explanatory comment/docstring informing the user that it performs filesystem writes.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This code reads sensitive credentials from environment variables and transmits them in an HTTP POST request to obtain an access token. While the operation is functionally expected for authentication, the file contains no user-facing prompt, log, comment, or docstring disclosing that environment-provided secrets will be sent over the network.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The audio-driven video builder defaults the language parameter to "cn", which imposes a specific locale choice unless the caller explicitly overrides it. The policy requires avoiding forced language or locale settings without user opt-in or clear justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The text-driven video builder also defaults the language parameter to "cn", creating the same locale policy issue by selecting a specific language automatically. No nearby documentation indicates this is a justified region-specific constraint or an explicit user choice.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The create_audio_driven_video_task wrapper exposes language with a default of "cn", meaning callers who omit the argument will still get a forced Chinese locale. This reinforces the locale policy violation at the public API surface.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The create_text_driven_video_task wrapper sets language to "cn" by default, again forcing a specific locale for callers who do not opt in. The file does not document this as a justified regional limitation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The upload_to_oss function reads a local file and sends its full contents via an HTTP PUT request to a remote sign_url, but the code provides no confirmation prompt, logging, print statement, or explanatory comment warning that local file data will be transmitted. For a code file, this matches the missing-warning criterion for network calls that transmit user or system data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The download_video function creates parent directories and writes the HTTP response body to output_path, but there is no confirmation, user-facing log, or explanatory comment indicating that local files will be created or overwritten. This is a file-write operation in a code file with no visible disclosure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The code retrieves a token and sends it as an HTTP header to the external service, which is credential handling and network transmission of sensitive authentication material. There is no user-facing notice, comment, or docstring in this file explaining that credentials are used and sent to a third-party endpoint.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The function submits user-provided text and voice parameters to a remote HTTP endpoint, which can affect user privacy because text content leaves the local environment. This file contains no confirmation prompt, logging, comment, or docstring that discloses this transmission to the user.

Content

No source excerpt is available for this finding.