Back to skill

Security audit

短剧剪辑与成片

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its video-editing purpose, but its renderer has a real file-overwrite boundary risk that users should review before installing.

Install only if you are comfortable running a local renderer over trusted project directories. Before rendering, avoid projects from untrusted collaborators or inspect/remove symlinks in the episode output tree; consider running in a sandbox or container with limited filesystem access. Use the default ffmpeg subtitle path unless you need Remotion, and install Remotion dependencies only from a trusted package source.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/edit_tool.py:1468
Finding

Project-controlled output symlinks can redirect rendering writes outside the project

Content
View full analysis

Vulnerability Details

File Location: scripts/edit_tool.py, lines 1468–1470, 1493, 1569–1572, 1583–1587, and 2218–2222
Vulnerability Type: Improper link resolution and unrestricted output redirection
Risk Level: Medium

Complete Code Snippet

python
output_root = episode / OUTPUT_DIRECTORY
segments_root = output_root / SEGMENT_DIRECTORY
segments_root.mkdir(parents=True, exist_ok=True)
python
segment = segments_root / f"{cut.cut_id}.mp4"
python
if cues:
    subtitle_path = output_root / "字幕.srt"
    subtitle_path.write_text(_build_srt(cues), encoding="utf-8")
python
if cues and renderer != "remotion":
    styled = styled_path = output_root / "字幕.ass"
    styled.write_text(
        _build_ass(cues, canvas["width"] or 1080, canvas["height"] or 1920),
        encoding="utf-8",
    )
python
props = output_root / "叠层.props.json"
props.write_text(
    json.dumps(_overlay_props(cues, layers, canvas, duration), ensure_ascii=False, indent=2),
    encoding="utf-8",
)

Other rendering destinations, including segment and final media files, are passed to ffmpeg with overwrite mode enabled:

python
command = [ffmpeg, "-hide_banner", "-loglevel", "error", "-y", "-i", str(joined)]

Technical Analysis

The renderer derives its output directory directly from the selected episode:

python
output_root = episode / OUTPUT_DIRECTORY

It then creates or reuses that path without checking whether the output directory, an intermediate component, or an individual output file is a symbolic link. Path.mkdir(..., exist_ok=True) accepts an existing symlink to a directory, and Path.write_text() follows an existing destination symlink.

The same trust issue affects files written by ffmpeg. Output destinations are supplied with -y, allowing existing destinations to be overwritten, but there is no preceding no-follow or resolved-pat ...[truncated 2094 chars]

Remediation
View remediation

Remediation Suggestions

  1. Resolve the project root, episode directory, and intended output root before rendering. Reject execution unless the episode and resolved output destination remain within the authorized project root.
  2. Reject symbolic links in every component of 制作成果/成片, including the output directory, segment directory, and existing destination files.
  3. Before every write, verify both the parent directory and destination using descriptor-based, no-follow operations rather than relying only on Path.resolve() checks that can be invalidated by races.
  4. For text outputs, open files with platform-supported protections such as os.open() with O_NOFOLLOW, restrictive permissions, and safe creation flags. Write to a securely created temporary file in the validated directory and atomically replace the destination.
  5. Before invoking ffmpeg, require the destination parent to be a validated real directory and reject any existing destination that is a symlink or non-regular file. Prefer rendering to securely created temporary paths followed by an atomic rename.
  6. Apply a strict filename-only grammar to cut_id before using it in segment filenames, disallowing slashes, path separators, dot components, and control characters.
  7. Add regression tests covering a symlinked output root, symlinked segment directory, and symlinked subtitle, properties, and final-media destinations.
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • 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
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (32)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

声明描述的是视频剪辑/后期流程管理能力,而代码仅处理字体资源是否就绪、是否会回退到浏览器默认字体,以及据此控制 Remotion 渲染流程。这不是对“剪成成片、记录镜序/声音/字幕/交付规格、调整节奏、导出素材”等能力的支撑性实现细节,而是一个独立的底层字体渲染保障模块。两者主目的明显不同,且代码没有体现任何与剪辑时间线、字幕编辑、音频处理或导出规格管理直接相关的行为,因此应判定为描述与行为不匹配。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The supplied code is a TypeScript design-token/utilities module for rendering screen text and subtitles in video output. It contains constants for fonts and colors, positioning values, and helper functions for entrance/exit/glitch animation based on frame timing. This does not implement the declared skill’s main purpose of editing short-drama footage into a finished cut, tracking edit decisions, handling shot order, audio, delivery specs, or exporting refined materials. While subtitle styling is loosely related to the declared mention of subtitles, this is only a narrow visual implementation detail and not the described editing capability. Therefore the code chunk materially differs from the declared purpose.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
80% confidence
Finding

The skill instructs use of file read/write operations and shell execution via Python tooling (edit_tool.py, ffmpeg, ffprobe) but does not declare any tool scope or permission boundaries. In an agent environment, missing explicit scoping increases the chance of unintended filesystem access or command execution beyond the episode/project directory, especially because many paths are user-controlled placeholders like 剧集/<EP> and --project-root.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The default prompt invokes the skill through a broad activation phrase without any explicit preconditions, scope limits, or user-confirmation requirements. This can cause the agent to trigger editing actions too eagerly or in the wrong context, especially if other workflows or untrusted inputs can reference the skill name, leading to unintended processing or task execution.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The string passed to delayRender is hard-coded in Chinese (加载字体). The policy requires flagging language or locale constraints when a skill forces a specific language without offering user choice or documenting a justified locale restriction.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The thrown error message is entirely in Chinese and there is no indication in this file that users can opt into that locale or choose another language. This creates a natural-language policy concern for forced locale behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The file contains fixed Chinese-language UI text in CHROME_TEXT and related display strings, which indicates the skill renders output in a single locale. Under the policy, forcing a specific language without offering user choice or documenting a justified locale constraint can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The function returns user-facing status/error messages entirely in Chinese, such as timeout and missing-font notices. In this file there is no indication that users can opt into this locale or that the skill is explicitly limited to a Chinese-language context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The file hard-codes a Simplified Chinese font family ("Noto Sans SC") and later uses Chinese rarity labels, which indicates the skill output is tailored to a specific language/locale. There is no visible user choice or documented justification in this file for forcing that locale, which can violate language/locale policy requirements.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The comments and constants embed Chinese labels such as 传说, 史诗, and 稀有 directly into shared rendering tokens. Because this file provides reusable display tokens, hard-coding one language without opt-in or documented regional scope is a natural-language locale policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This markdown file contains all user-facing instructions in Chinese, and there is no indication that the user can choose another language or that the skill is intentionally restricted to a Chinese-speaking or region-specific context. That creates a natural-language policy concern because it effectively forces a specific language without user opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The document presents all operational instructions in Chinese and does not indicate that users may choose another language or that the skill is intentionally limited to a Chinese-language context. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The entire skill file is written as prescriptive guidance in Chinese and does not indicate that users may choose another language or locale. Under the policy rule for language/locale choice, this can be a natural-language policy violation when no opt-in or justified locale restriction is documented.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The entire skill file is written exclusively in Chinese, including headings, rules, and workflow guidance, with no indication that users may choose another language or that the skill is intentionally limited to a Chinese-only audience. Under the policy, forcing a specific language without opt-in is a natural-language locale violation.

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/edit_tool.py (reported line 872)May include surrounding context.

python
def probe_duration(media: Path) -> float:
    probe = _require("ffprobe")
    result = subprocess.run(
        [probe, "-v", "error", "-show_entries", "format=duration",
         "-of", "default=nw=1:nk=1", str(media)],
        capture_output=True, text=True, check=False,

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/edit_tool.py (reported line 884)May include surrounding context.

python
def probe_stream(media: Path) -> dict[str, Any]:
    probe = _require("ffprobe")
    result = subprocess.run(
        [probe, "-v", "error", "-select_streams", "v:0", "-show_entries",
         "stream=width,height,r_frame_rate", "-show_entries", "format=duration",
         "-of", "json", str(media)],

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/edit_tool.py (reported line 922)May include surrounding context.

python
"""(sample rate, channel layout) of the first audio stream; None when it has none."""

    probe = _require("ffprobe")
    result = subprocess.run(
        [probe, "-v", "error", "-select_streams", "a:0", "-show_entries",
         "stream=sample_rate,channels,channel_layout", "-of", "json", str(media)],
        capture_output=True, text=True, check=False,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
83% confidence
Finding

This code decodes attacker-controlled media with ffmpeg and captures the entire raw output into memory. A crafted or simply very large audio file can cause excessive memory consumption or trigger parser vulnerabilities in ffmpeg, leading to denial of service in environments where untrusted project assets are processed.

Content

Scanner excerpt · scripts/edit_tool.py (reported line 1027)May include surrounding context.

python
"""A sound file's length and where its sound starts and stops, decoded small and mono."""

    ffmpeg = _require("ffmpeg")
    result = subprocess.run(
        [ffmpeg, "-v", "error", "-i", str(media), "-ac", "1", "-ar", str(AUDIBLE_RATE),
         "-f", "s16le", "-"],
        capture_output=True, check=False,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
81% confidence
Finding

This helper captures rawvideo output from ffmpeg directly into memory, and callers build commands from project media inputs. A maliciously large or malformed file can force high memory use or heavy CPU consumption during decoding, creating a denial-of-service condition during rendering or analysis.

Content

Scanner excerpt · scripts/edit_tool.py (reported line 2055)May include surrounding context.

python
def _sampled_stats(command: list[str]) -> Optional[ChannelStats]:
    result = subprocess.run(
        command + ["-pix_fmt", "rgb24", "-f", "rawvideo", "-"], capture_output=True, check=False
    )
    if result.returncode != 0 or len(result.stdout) < 3:

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/edit_tool.py (reported line 2084)May include surrounding context.

python
"""

    common = f"I={target}:TP=-1.5:LRA=11"
    result = subprocess.run(
        [ffmpeg, "-hide_banner", "-nostats", "-i", str(media),
         "-af", f"loudnorm={common}:print_format=json", "-f", "null", "-"],
        capture_output=True, text=True, check=False,

Rp1

Medium
Category
MCP Rug Pull
Confidence
93% confidence
Finding

The Remotion path depends on npx, which may resolve and execute packages from the npm ecosystem if the workspace state is incomplete or manipulated. In a media-rendering tool that already writes and executes build assets outside the repository, this creates meaningful supply-chain exposure and makes compromise of npm dependencies particularly dangerous.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
91% confidence
Finding

The code invokes npx remotion render in a workspace whose dependencies are installed out-of-band and not pinned or integrity-verified at runtime. This increases supply-chain risk: if the workspace package set or npm resolution is compromised, executing npx/remotion will run attacker-controlled JavaScript with the user's privileges.

Content

Scanner excerpt · scripts/edit_tool.py (reported line 2224)May include surrounding context.

python
encoding="utf-8",
    )
    overlay = output_root / "叠层.webm"
    result = subprocess.run(
        [npx, "remotion", "render", REMOTION_COMPOSITION, str(overlay),
         f"--props={props}", "--log=error",
         f"--concurrency={max(1, concurrency)}"],

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
78% confidence
Finding

This subprocess decodes video frames with ffmpeg and captures rawvideo output, which can be abused by oversized or hostile media to consume substantial memory and CPU. In a content-processing skill like this, project assets are central inputs, so resource-exhaustion risk is more relevant than in a tool that only touches trusted local files.

Content

Scanner excerpt · scripts/edit_tool.py (reported line 2696)May include surrounding context.

python
def _segment_colour(ffmpeg: str, path: Path) -> Optional[tuple[float, float]]:
    """Mean luma and blue-red difference of one segment, on a 0-255 scale."""

    result = subprocess.run(
        [ffmpeg, "-v", "error", "-i", str(path), "-vf", "fps=2,scale=96:-1",
         "-pix_fmt", "rgb24", "-f", "rawvideo", "-"],
        capture_output=True,

Static analysis

No suspicious patterns detected.