Back to skill

Security audit

bilibili-video-analyzer

Security checks for vulnerabilities and agentic risk

Overview

The skill broadly does what it claims, but it handles Bilibili login/video data and contains unsafe parsing, dependency, and disclosure gaps that users should review before installing.

Install only in an isolated environment, avoid using a high-value Bilibili account, review dependency versions before installing, and do not process private or sensitive videos unless you are comfortable storing transcripts/screenshots locally and sending transcript content to an external LLM. The eval() parsing issue should be fixed before using untrusted media.

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/screenshot_tool.py:365
Finding
Arbitrary Python Expression Evaluation of Media-Derived Metadata<![CDATA[ ## Vulnerability Details **File Location**: `scripts/screenshot_tool.py:365-372` **Vulnerability Type**: Unsafe use of `eval()` on FFprobe output **Risk Level**: High ### Vulnerable Code ```python # Extract information info = { 'duration': float(data.get('format', {}).get('duration', 0)), 'width': int(video_stream.get('width', 0)), 'height': int(video_stream.get('height', 0)), 'fps': eval(video_stream.get('r_frame_rate', '0/1')) } return info ``` ### Technical Analysis The `r_frame_rate` value is obtained from JSON produced by FFprobe after processing a potentially untrusted video file. The value is passed directly to Python's `eval()`, which evaluates arbitrary Python expressions rather than only parsing a rational frame rate. The expected format is a fraction such as `30000/1001`. Evaluating that format does not require `eval()`. If a crafted media container, compromised FFprobe executable, or unexpected metadata-processing path causes an attacker-controlled expression to appear in `r_frame_rate`, the expression will execute in the Python process. Exploitability through an ordinary media file depends on whether the installed FFprobe version and relevant demuxer normalize the field before serialization. Nevertheless, this remains a dangerous local code-execution sink and violates secure parsing requirements. ### Attack Path 1. An attacker supplies or publishes a specially crafted video file. 2. The user processes the file with `screenshot_tool.py` or another caller of `get_video_info()`. 3. FFprobe parses the file and returns stream metadata as JSON. 4. The application retrieves the `r_frame_rate` string. 5. The string is evaluated by Python's `eval()`. 6. If an executable expression reaches this field, it runs with the privileges of the user running the analyzer. An equivalent path exists if an attacker can replace or wrap the `ffprobe` executable resolved through the process environment. ### Impact Assessment Successful e ...[truncated 512 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Replace `eval()` with strict rational-number parsing: ```python from fractions import Fraction frame_rate = video_stream.get('r_frame_rate', '0/1') try: fps_fraction = Fraction(frame_rate) fps = float(fps_fraction) if fps_fraction.denominator != 0 else 0.0 except (ValueError, ZeroDivisionError): fps = 0.0 info = { 'duration': float(data.get('format', {}).get('duration', 0)), 'width': int(video_stream.get('width', 0)), 'height': int(video_stream.get('height', 0)), 'fps': fps, } ``` Additional hardening should include: 1. Validate the source value against an allowlist such as `^[0-9]+/[1-9][0-9]*$`. 2. Reject unexpectedly long values before parsing. 3. Resolve FFprobe from a trusted absolute path or verify the executable selected through `PATH`. 4. Process untrusted media in a restricted subprocess or sandbox where practical. 5. Add regression tests proving that Python expressions and malformed fractions cannot execute. ]]>

other

Warning
Location
scripts/llm_analyzer.py:39
Finding
Indirect Prompt Injection Through Untrusted Video Metadata and Subtitles<![CDATA[ ## Vulnerability Details **File Location**: `scripts/llm_analyzer.py:39-60` **Vulnerability Type**: Indirect prompt injection **Risk Level**: Medium ### Vulnerable Code ```python prompt = f"""你是一位专业的学术内容分析专家。请深度分析以下学术视频的字幕内容,提取关键学术信息。 **视频信息**: - 标题: {title} - UP主: {author} - BV号: {bvid} - 时长: {duration_str} ({duration}秒) **完整字幕内容**: ``` {srt_content} ``` **分析要求**: 1. **内容摘要**: 用100-200字概括视频核心内容,使用学术化表述 2. **章节划分**: 根据内容逻辑划分3-6个章节,每章节包含时间范围和内容描述 3. **知识点提取**: 提取10-20个关键知识点,按重要程度排序,包含详细说明 4. **关键截图**: 识别6-10个需要截图的关键时间点(图表、公式、演示、重要概念等) 5. **专业术语**: 提取10-15个重要的专业术语及其定义 ``` ### Technical Analysis The video title, uploader name, identifier, and complete subtitle transcription are interpolated directly into the same natural-language prompt that contains the model's task instructions. The prompt does not explicitly tell the model that video metadata and subtitle content are untrusted data whose embedded instructions must never be followed. Markdown code fences provide visual formatting but do not establish a security boundary for an LLM. Subtitle text can also contain closing code fences or instruction-like content. An attacker controlling a Bilibili video's title, spoken content, or subtitle track can therefore insert instructions such as requests to ignore the analysis task, fabricate results, include attacker-selected links, or choose maliciously manipulated screenshot timestamps. The subsequent validation checks JSON structure and basic types, but it does not verify semantic fidelity, prohibit links or HTML, constrain timestamps to the video duration, or detect prompt-injection artifacts. ### Attack Path 1. An attacker publishes a video with adversarial instructions in its title, subtitles, or spoken content. 2. A victim provides the video URL to the analyzer. 3. The tool downloads and transcribes the video. 4. `build_analysis_prompt()` places the adversarial content directly into the LLM prompt. 5. The external LLM follows some or all of the e ...[truncated 923 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add explicit model instructions stating that titles, metadata, and subtitles are untrusted data and that instructions found inside them must be ignored. 2. Delimit untrusted content with a robust structured representation, such as a JSON object passed as a data field, rather than relying only on Markdown fences. 3. Escape or encode delimiter sequences contained in untrusted fields. 4. Separate task instructions from untrusted content using system/developer messages when an API-based integration is introduced. 5. Validate the response against a strict JSON Schema, including: - Maximum string and array lengths - Finite numeric values only - Nonnegative timestamps - Timestamps no greater than the video duration - Allowed enumeration values - Rejection of unexpected properties 6. Detect or reject active URLs and raw HTML unless they are explicitly required. 7. Require user review of generated content before screenshots are captured or reports are opened. 8. Consider a second validation pass that checks whether each result is supported by the transcript rather than treating the first LLM response as trusted. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/report_generator.py:92
Finding
Unsanitized LLM and Video Content Written to Markdown Reports<![CDATA[ ## Vulnerability Details **File Location**: `scripts/report_generator.py:92-145` **Vulnerability Type**: Markdown and HTML content injection **Risk Level**: Medium ### Vulnerable Code ```python # === Title === lines.append(f"# 《{title}》学习笔记") lines.append("") # === Video information overview === duration = video_info.get('duration', 0) duration_str = format_duration(duration) kp_count = len(analysis.get('knowledge_points', [])) lines.append(f"**视频时长**: {duration_str} | **知识点**: {kp_count} 个") lines.append("") lines.append("---") lines.append("") # === Knowledge-point cards === knowledge_points = analysis.get('knowledge_points', []) for i, kp in enumerate(knowledge_points, 1): title_kp = kp.get('title', f'知识点 {i}') core_concept = kp.get('core_concept', kp.get('content', '')) details = kp.get('details', '') key_points = kp.get('key_points', []) timestamp = kp.get('timestamp') # Knowledge-point title lines.append(f"## 📌 {i}. {title_kp}") lines.append("") # Core concept lines.append(f"**核心概念**: {core_concept}") lines.append("") lines.append("") lines.append("") # Find a corresponding screenshot closest_screenshot = None min_diff = 10.0 if timestamp: for sc_time, sc_path in screenshots.items(): diff = abs(sc_time - timestamp) if diff < min_diff: min_diff = diff closest_screenshot = sc_path # Insert screenshot if closest_screenshot: rel_path = Path(closest_screenshot).relative_to(output_dir) lines.append(f'<img src="{rel_path}" width="600" alt="知识点配图"/>') lines.append("") lines.append("") # Detailed explanation if details: lines.append("### 📖 详细说明") lines.append("") lines.append(details) lines.append("") ``` The same raw insertion pattern is also used for key points and summary fields later in the function. ### Technical Analysis The ...[truncated 2189 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Treat every value originating from video metadata or LLM output as untrusted. 2. Escape Markdown metacharacters in fields intended to be plain text, including titles and short scalar values. 3. Sanitize fields intentionally allowed to contain Markdown with an allowlist-based Markdown or HTML sanitizer. 4. Disable raw HTML in the recommended Markdown rendering workflow. 5. Prohibit remote images and restrict links to approved schemes such as `https`. 6. Reject dangerous schemes including `javascript:`, `data:`, and `file:` where links are permitted. 7. Escape HTML attribute values before inserting screenshot paths. 8. Verify that screenshot paths resolve beneath `output_dir` before computing or rendering relative paths. 9. Add maximum lengths for all report fields to prevent oversized output and renderer exhaustion. 10. Add tests using payloads containing raw HTML, external images, nested links, malformed attributes, and renderer-specific scripts. ]]>

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding
Unpinned Third-Party Dependencies Without Integrity Verification<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:1-2` **Vulnerability Type**: Dependency supply-chain exposure **Risk Level**: Medium ### Vulnerable Code ```text railgun-bili-tools>=1.2.0 openai-whisper>=20231117 ``` Related installation guidance in `SKILL.md:35-38` is: ```bash pip install railgun-bili-tools ``` ### Technical Analysis Both dependencies use open-ended lower-bound constraints. A future package version satisfying these constraints can be installed without any project review. No lock file, exact version, package hash, or integrity-verification procedure is provided. This is particularly sensitive for `railgun-bili-tools`, because the project imports its authentication and parser modules directly: ```python from bilibili_dl.auth import BilibiliAuth from bilibili_dl.parser import BilibiliParser ``` The dependency therefore executes inside the analyzer process and handles Bilibili login credentials. `openai-whisper` and its transitive dependencies also execute local code and may download model assets. The audit did not establish that either named package is currently malicious. The vulnerability is the absence of version and artifact integrity controls, which increases exposure to package-account compromise, malicious future releases, dependency substitution, and unexpected breaking behavior. ### Attack Path 1. A dependency publisher account or package-distribution channel is compromised, or a malicious future release is published. 2. The malicious version still satisfies the project's `>=` constraint. 3. A user installs or upgrades the project dependencies. 4. The package executes during installation, import, authentication, video download, or transcription. 5. Malicious package code gains the privileges and accessible data of the invoking user. ### Impact Assessment A compromised dependency could obtain arbitrary code execution under the invoking user's account. Because the downloader dependency participates in au ...[truncated 392 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin every direct dependency to an explicitly reviewed version. 2. Generate and commit a lock file that also constrains transitive dependencies. 3. Use hash verification, for example with `pip install --require-hashes`. 4. Download packages only from an explicitly configured trusted index. 5. Review package ownership, release history, and source repository before updating. 6. Automate vulnerability and provenance scanning for dependency updates. 7. Test updates in an isolated environment before deployment. 8. Avoid installing or running the analyzer as root or with `sudo`. 9. Isolate credential-bearing downloader operations from transcription and report-generation components where practical. 10. Document a controlled dependency-update process rather than recommending unconstrained installation. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (36)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
A second description/behavior mismatch finding points to the same core issue: the skill claims link-based Bilibili video analysis and report generation, while the shown implementation excerpts primarily operate on local artifacts such as SRT files and FFmpeg commands. This can mislead operators into granting broader trust or access than warranted and obscures the true attack surface.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
A second description/behavior mismatch finding points to the same core issue: the skill claims link-based Bilibili video analysis and report generation, while the shown implementation excerpts primarily operate on local artifacts such as SRT files and FFmpeg commands. This can mislead operators into granting broader trust or access than warranted and obscures the true attack surface.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
请开始分析并返回标准JSON格式的结果。"""
    
    return prompt


def interactive_analyze(video_info: Dict, srt_content: str) -> Dict[str, Any]:
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

eval() call detected

High
Category
Dangerous Code Execution
Content
'duration': float(data.get('format', {}).get('duration', 0)),
            'width': int(video_stream.get('width', 0)),
            'height': int(video_stream.get('height', 0)),
            'fps': eval(video_stream.get('r_frame_rate', '0/1'))
        }
        
        return info
Confidence
99% confidence
Finding
Using eval() on ffprobe-derived data is dangerous because it executes arbitrary Python expressions if the parsed value is attacker-controlled or if ffprobe output is spoofed or malformed. In a skill that analyzes user-supplied videos, this creates a plausible code-execution path in the host process rather than merely a parsing bug.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The README promotes video downloading, login use, subtitle transcription, and third-party AI analysis, but does not warn users that credentials may be used, copyrighted/private content may be processed, and transcripts or metadata may be transmitted to external services such as Claude or Whisper-backed components. In this skill context, the omission is more significant because the workflow explicitly involves authentication and cloud AI processing, which can expose account, content, or privacy-sensitive data if users are not informed.

Lp3

Medium
Category
MCP Least Privilege
Confidence
85% confidence
Finding
The skill documents shell execution, file reads, and file writes, but does not declare any tool scope such as allowed-tools or permissions. This creates an authorization and review gap: an agent may invoke filesystem and shell capabilities that users or platform policy did not explicitly approve, including downloading content and writing large local artifacts.

Missing User Warnings

Medium
Confidence
83% confidence
Finding
The skill omits an explicit warning that it downloads third-party video content and stores potentially large local files and screenshots. This is risky because users may not realize the privacy, copyright, storage, and retention implications before the agent performs disk- and content-handling actions.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The listed trigger phrases such as "帮我总结这个视频的知识点", "生成这个视频的学习报告", and "提取这个视频的关键内容" are generic video-summary requests and are not limited to Bilibili links or educational content. Without tighter constraints or negative examples, the skill could be invoked for unrelated video-analysis tasks.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
**Ubuntu/Debian:**
```bash
sudo apt install ffmpeg
```

**Windows:**
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding
Suspicious Unicode normalization or mixed-script content

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
该最佳实践文档从标题到全部操作说明均固定为中文,且未说明这是面向中文用户或特定区域场景的限定文档。根据语言/locale 政策,若技能内容强制单一语言而无用户选择或明确、合理的区域性说明,属于自然语言层面的策略问题。

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding
Suspicious Unicode normalization or mixed-script content

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This markdown checklist appears to require Chinese as the operating language for the skill content, and there is no indication that users may choose another language or that the restriction is justified by a region-specific purpose. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The script's banner, prompts, help text, and status messages are written in Chinese throughout, which effectively forces a specific language for all users. The file does not provide any opt-in language selection or document that the tool is intentionally limited to a Chinese-speaking audience.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
print(f"执行命令: {' '.join(cmd)}\n")
    
    try:
        result = subprocess.run(cmd, check=True)
        
        if result.returncode == 0:
            # 查找下载的视频文件
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
print(f"执行命令: {' '.join(cmd)}\n")
    
    try:
        result = subprocess.run(cmd, check=True)
        
        if result.returncode == 0:
            # 查找下载的视频文件
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The full subtitle content is read and passed into an LLM analysis function without any visible consent, warning, or privacy guardrails. If the analyzer sends content to a remote model provider, sensitive or copyrighted transcript material could be transmitted off-device unexpectedly.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The prompt text requires the LLM to analyze and return results entirely in Chinese, including Chinese academic phrasing and field descriptions. This imposes a language/locale choice on the user without opt-in, which matches the policy category for forced language constraints.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The module description explicitly defines the skill as a Chinese-language markdown report generator. Across the file, user-facing output and generated report labels are fixed in Chinese, with no indication that the user can choose another language or locale.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The module description, docstrings, CLI usage text, and user-facing messages are all presented in Chinese, which effectively forces a specific language for interaction. The file does not offer an alternative language or explain that the tool is intentionally limited to a Chinese-speaking context.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
"❌ 未找到 FFmpeg!\n\n"
            "请先安装 FFmpeg:\n"
            "  macOS:    brew install ffmpeg\n"
            "  Ubuntu:   sudo apt install ffmpeg\n"
            "  Windows:  从 https://ffmpeg.org/download.html 下载\n"
        )
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
)
    
    try:
        result = subprocess.run(
            ['ffmpeg', '-version'],
            capture_output=True,
            text=True,
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
# 重试机制
    for attempt in range(retry):
        try:
            result = subprocess.run(
                cmd,
                capture_output=True,
                text=True,
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
]
    
    try:
        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,
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
]
    
    try:
        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/screenshot_tool.py:371