Back to skill

Security audit

YouTube Chinese Subtitle Burn-in

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its YouTube subtitle purpose, but it can write raw user feedback into its own future instructions and repackage itself, which needs human review before installation.

Install only if you are comfortable with a YouTube media-processing skill that runs ffmpeg/yt-dlp and writes output files locally. Treat its feedback feature carefully: do not let untrusted users submit reusable feedback, and review any changes to workflow.md, quality-gates.md, or SKILL.md before re-packaging or reusing the skill.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Findings (1)

T02 · Agent Memory Poisoning

Error
Location
scripts/record_feedback.py:48
Finding
Persistent Agent Instruction Poisoning Through Unsanitized Feedback<![CDATA[ ## Vulnerability Details **File Location**: `scripts/record_feedback.py:48-74` **Supporting Locations**: `SKILL.md:28-34`, `SKILL.md:119-126`, `references/workflow.md:306-315` **Vulnerability Type**: Persistent instruction injection through user-controlled feedback **Risk Level**: High ### Vulnerable Code ```python def main() -> int: parser = argparse.ArgumentParser(description="Record user subtitle feedback and optionally update reusable gates.") parser.add_argument("--issue", required=True) parser.add_argument("--category", required=True) parser.add_argument("--fix", required=True) parser.add_argument("--video", default="") parser.add_argument("--timestamp", default="") parser.add_argument("--cause", default="") parser.add_argument("--reusable", choices=["yes", "no"], default="yes") args = parser.parse_args() entry = f""" ### {date.today().isoformat()} - {args.category} - {args.issue} Date: {date.today().isoformat()} Video/output: {args.video or "not specified"} Timestamp: {args.timestamp or "not specified"} Category: {args.category} User issue: {args.issue} Confirmed cause: {args.cause or "to be confirmed during review"} Fix applied: {args.fix} Reusable: {args.reusable} SOP update: {"required" if args.reusable == "yes" else "not required"} Quality gate update: {"required" if args.reusable == "yes" else "not required"} """ append_under_heading(LEDGER, "## Entries", entry) print(f"Recorded feedback in {LEDGER}") if args.reusable == "yes": marker = f"Feedback gate: {args.category} - {args.issue}" gate = f"| <!-- {marker} --> {args.category}: {args.issue} | Same or similar user-visible subtitle problem appears during review | {args.fix} |" workflow = f""" <!-- Feedback workflow: {args.category} - {args.issue} --> ## Feedback Prevention: {args.category} When this pattern appears: {args.issue} Prevent it by: {args.fix} """ gate_changed = insert_before_heading_onc ...[truncated 4004 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Do not write raw feedback into instruction files** - Store feedback in a structured data file such as JSON. - Keep user observations distinct from trusted workflow rules. - Treat ledger entries as untrusted data that must never be followed as instructions. 2. **Require trusted approval for workflow changes** - Generate proposed changes in a separate review file. - Require explicit human approval before modifying `workflow.md`, `quality-gates.md`, or `SKILL.md`. - Do not automatically repackage a Skill containing unreviewed feedback. 3. **Validate every feedback field** - Replace free-form categories with a fixed allowlist. - Set conservative maximum lengths. - Reject newline characters, control characters, null bytes, and bidirectional text controls where single-line values are expected. - Validate timestamps and other structured fields with strict parsers. 4. **Escape presentation syntax** - Escape Markdown table separators, headings, HTML comment delimiters, backticks, and other formatting tokens before writing display-only records. - Do not rely on escaping alone for instruction files; approval and data/instruction separation remain necessary. 5. **Change the persistence default** - Default `--reusable` to `no`. - Require an explicit reviewed option to propose a reusable rule. - Ensure a reusable rule contains trusted, normalized text rather than the original user submission. 6. **Add defensive guidance** - State explicitly that text in feedback ledgers and generated proposals is untrusted. - Instruct the Agent not to execute or follow directives embedded in issue descriptions, subtitle text, metadata, or proposed fixes. 7. **Add security tests** - Test multiline values, Markdown headings, HTML comments, code fences, table separators, and instruction-like phrases. - Verify that malicious test inputs cannot alter trusted workflow semantics or become automatica ...[truncated 28 chars]
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (38)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The skill instructs the agent to modify internal workflow, quality-gate, and feedback-ledger documentation based on user feedback and then re-package the skill. Allowing user-driven updates to the skill's own operational documents creates a prompt-injection and persistence risk: malicious user input could be written into trusted reference files and influence future runs.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The skill instructs the agent to modify internal workflow, quality-gate, and feedback-ledger documentation based on user feedback and then re-package the skill. Allowing user-driven updates to the skill's own operational documents creates a prompt-injection and persistence risk: malicious user input could be written into trusted reference files and influence future runs.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill instructs the agent to modify internal workflow, quality-gate, and feedback-ledger documentation based on user feedback and then re-package the skill. Allowing user-driven updates to the skill's own operational documents creates a prompt-injection and persistence risk: malicious user input could be written into trusted reference files and influence future runs.

Unvalidated Output Injection

High
Category
Output Handling
Content
args.out_dir.mkdir(parents=True, exist_ok=True)
    for index, seconds in enumerate(times, 1):
        output = args.out_dir / format_name(index, seconds)
        result = subprocess.run(
            [
                "ffmpeg",
                "-y",
Confidence
95% confidence
Finding
Model output is used without validation or sanitization. Unvalidated output injected into downstream contexts (SQL, shell, HTML) enables injection attacks and arbitrary code execution.

Unvalidated Output Injection

High
Category
Output Handling
Content
args.out_dir.mkdir(parents=True, exist_ok=True)
    for index, seconds in enumerate(times, 1):
        output = args.out_dir / format_name(index, seconds)
        result = subprocess.run(
            [
                "ffmpeg",
                "-y",
Confidence
95% confidence
Finding
Model output is used without validation or sanitization. Unvalidated output injected into downstream contexts (SQL, shell, HTML) enables injection attacks and arbitrary code execution.

Unvalidated Output Injection

High
Category
Output Handling
Content
args.out_dir.mkdir(parents=True, exist_ok=True)
    for index, seconds in enumerate(times, 1):
        output = args.out_dir / format_name(index, seconds)
        result = subprocess.run(
            [
                "ffmpeg",
                "-y",
Confidence
95% confidence
Finding
Model output is used without validation or sanitization. Unvalidated output injected into downstream contexts (SQL, shell, HTML) enables injection attacks and arbitrary code execution.

Unvalidated Output Injection

High
Category
Output Handling
Content
draw_subtitles(image, current, style_profile)
        image.save(frame_path)

    encode = subprocess.run(
        [
            "ffmpeg",
            "-y",
Confidence
95% confidence
Finding
Model output is used without validation or sanitization. Unvalidated output injected into downstream contexts (SQL, shell, HTML) enables injection attacks and arbitrary code execution.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill explicitly relies on shell execution and file read/write operations, but it does not declare any tool scope or permission boundaries. That creates unnecessary privilege ambiguity: an agent could invoke broad local commands or modify files outside the intended workspace without policy-level restriction, especially because the workflow includes downloaders, media processors, and documentation updates.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The invocation text is broad enough to activate on many generic video-editing, translation, thumbnail, or review requests. Over-broad triggering can cause the agent to enter a shell/file/network-capable workflow in contexts where the user did not intend YouTube downloading, local file processing, or subtitle-burning operations, increasing the chance of unsafe tool use and overreach.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The overview states the skill will turn a YouTube video into a Simplified Chinese or optional bilingual output, making Chinese the default output language. This is a language-policy concern because the file sets a specific locale/language behavior by default rather than presenting it as a user choice or opt-in.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The instruction 'Default to Chinese-only unless the user asks for bilingual subtitles' hard-codes a language preference. Because the file does not frame this as a user-selected option, it can violate language/locale policy expectations around user choice.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
| 2026-05-16 | cover | Add “中文字幕” and YouTube-style author information to the cover when requested | Cover translation needed a concrete output mode, not only a yes/no preference | yes | Add Cover Processing Mode with placement, preservation, versioned output, and visual check rules |
| 2026-05-16 | description | Video description should be downloaded and translated to Chinese when needed | Workflow retained video/subtitle/cover files but did not define description handling | yes | Extract original description, translate non-Chinese descriptions with the current agent model, and preserve proper nouns, URLs, and timestamps |
| 2026-05-16 | model portability | Skill should work with non-GPT agent models such as Minimax when the agent can run the local workflow | Translation instructions were worded around Codex/GPT as the default model | yes | Use current agent model wording and neutral translation-batch paths; keep old Codex batch script as a compatibility alias |
| 2026-05-16 | bilingual layout | Bilingual subtitles can become too tall or duplicate burned-in English subtitles | Chinese-only layout rules were reused without checking source subtitles or total subtitle height | yes | Add optional bilingual ASS generation, source subtitle check frames, and design confirmation frames before full burn |
| 2026-05-16 | bilingual layout | Bilingual subtitle video showed stray `N` characters and Chinese/English lines felt mismatched | ASS newline escaping leaked into visible text, and semantic Chinese screens were paired with fragmented rolling English captions | yes | Add visible newline artifact gate and require matched cue boundaries when semantic Chinese plus rolling English looks messy |
| 2026-05-16 | bilingual layout | Bilingual subtitles looked messier than Chinese-only | English was treated as an equally prominent second subtitle and exact matching could fragment the Chinese reading rhythm | yes | Default bilingual mode to Chinese-primary / English-auxiliary, smalle
...[truncated 25 chars]
Confidence
75% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The gate requires retaining a Chinese translated description whenever the original description is not Chinese, which imposes a specific language outcome by default. The file also repeatedly centers Chinese-only or Chinese-primary output without stating that the user can choose another language, which conflicts with the policy against forcing a locale without opt-in.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The file requires that edited covers include the fixed Chinese label `中文字幕` and source attribution, which can cause the system to alter user assets by default once cover editing is requested. Even in a Chinese-subtitle skill, forcing specific overlay text without explicit per-edit confirmation can produce unwanted or misleading modifications, especially when the user asked only for subtitle generation or wanted the thumbnail preserved.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The template hard-codes a 'Chinese description' field and the checklist later requires retaining it when the original is not Chinese, which can normalize translation and transformation of third-party metadata without an explicit user request or documented justification. In a workflow that processes YouTube content, this increases the risk of unauthorized localization, policy drift, and delivery of modified metadata the user did not ask for.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The checklist requires every edited cover to include `中文字幕` regardless of whether the user asked for cover editing, requested preservation of original text, or authorized localization. In this skill context, that creates a strong workflow bias toward altering thumbnails and adding Chinese text to third-party artwork, which can misrepresent source media and cause unwanted or unauthorized content modification.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The SOP says that if the user only provides a URL, the process should default to Simplified Chinese hard subtitles. This imposes a language/locale choice automatically rather than offering the user a choice or requiring explicit opt-in.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def probe(video: Path) -> tuple[int, int, float]:
    result = subprocess.run(
        [
            "ffprobe",
            "-v",
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
frame_size = width * height * 3
    args.out.parent.mkdir(parents=True, exist_ok=True)

    decoder = subprocess.Popen(
        ["ffmpeg", "-v", "error", *ffmpeg_input_args(args.video, args.start, args.duration), "-f", "rawvideo", "-pix_fmt", "rgb24", "-"],
        stdout=subprocess.PIPE,
    )
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
["ffmpeg", "-v", "error", *ffmpeg_input_args(args.video, args.start, args.duration), "-f", "rawvideo", "-pix_fmt", "rgb24", "-"],
        stdout=subprocess.PIPE,
    )
    encoder = subprocess.Popen(
        [
            "ffmpeg",
            "-y",
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def has_filter(ffmpeg: str, name: str) -> bool:
    result = subprocess.run([ffmpeg, "-hide_banner", "-filters"], check=False, text=True, capture_output=True)
    return result.returncode == 0 and re.search(rf"\b{name}\b", result.stdout) is not None
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The script embeds Chinese-specific punctuation and phrase rules and treats only styles prefixed with "Chinese" and "English" as the bilingual model, which imposes a specific language/locale policy in natural-language logic. There is no opt-in, language selection, or documented justification that this checker is intentionally limited to Chinese/English subtitle workflows.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
output_template,
        args.url,
    ]
    result = subprocess.run(command, text=True, capture_output=True, check=False)
    if result.returncode != 0:
        print(result.stdout, end="")
        print(result.stderr, end="")
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def get_duration(video: Path) -> float:
    result = subprocess.run(
        [
            "ffprobe",
            "-v",
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def get_duration(video: Path) -> float:
    result = subprocess.run(
        ["ffprobe", "-v", "error", "-print_format", "json", "-show_format", str(video)],
        check=False,
        text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Static analysis

No suspicious patterns detected.