Back to skill

Security audit

video-analyzer

Security checks for vulnerabilities and agentic risk

Overview

This video analyzer performs its stated job, but it needs review because it uploads full analysis results by default and has risky credential and dependency behavior.

Install only if you are comfortable with transcripts and analyses being sent to configured LLM providers and, by default, published into Feishu. Before use, disable Feishu publishing unless explicitly needed, verify FEISHU_DOMAIN is not set to an arbitrary endpoint, avoid sensitive videos, and install pinned dependencies in an isolated environment instead of allowing runtime auto-installation.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
feishu_publisher.py:152
Finding
Feishu Credentials and Access Tokens Can Be Sent to an Arbitrary or Plaintext Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `feishu_publisher.py:152-173, 206-219, 228-236` **Vulnerability Type**: Arbitrary authentication endpoint and missing HTTPS enforcement **Risk Level**: High ### Complete Code Snippet ```python def _resolve_credentials(self) -> FeishuCredentials: """Resolve app credentials from args > env > openclaw.json.""" app_id = self.app_id or os.getenv("FEISHU_APP_ID", "").strip() app_secret = self.app_secret or os.getenv("FEISHU_APP_SECRET", "").strip() domain = self.domain or os.getenv("FEISHU_DOMAIN", "").strip() if not app_id or not app_secret or not domain: ocfg = self._read_openclaw_feishu_config() app_id = app_id or str(ocfg.get("appId") or "").strip() app_secret = app_secret or str(ocfg.get("appSecret") or "").strip() domain = domain or str(ocfg.get("domain") or "").strip() if not app_id or not app_secret: raise FeishuPublishError( "Missing Feishu app credentials. Set FEISHU_APP_ID/FEISHU_APP_SECRET " "or configure channels.feishu.appId/appSecret in openclaw.json" ) return FeishuCredentials( app_id=app_id, app_secret=app_secret, domain=domain or "feishu", ) @staticmethod def _default_openclaw_config_path() -> Path: openclaw_home = os.getenv("OPENCLAW_HOME", "").strip() if openclaw_home: return Path(openclaw_home).expanduser().resolve() / "openclaw.json" return Path.home().resolve() / ".openclaw" / "openclaw.json" @staticmethod def _domain_to_api_base(domain: str) -> str: value = (domain or "feishu").strip().lower().rstrip("/") if value.startswith("http://") or value.startswith("https://"): return value if value == "lark": return "https://open.larksuite.com" return "https://open.feishu.cn" def _get_tenant_access_token( self, *, api_base: str, app_id: str, app_secret: str ) -> str: if self._tenant_access_token: ret ...[truncated 2005 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace arbitrary domain handling with a strict allowlist: - `https://open.feishu.cn` - `https://open.larksuite.com` 2. Reject all `http://` URLs and any URL containing user information, unexpected ports, fragments, or nonstandard paths. 3. Do not allow environment variables or general channel configuration to provide an unrestricted API base URL. 4. Disable or strictly validate redirects so credentials cannot be redirected to another hostname. 5. Resolve the hostname and apply egress controls where possible. 6. Keep credentials in a dedicated secret manager and grant the Feishu application only the document and wiki scopes required for publishing. 7. Add tests confirming that arbitrary hosts and plaintext endpoints are rejected before credentials are loaded or transmitted. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
core.py:20
Finding
Full Video Transcript and Analysis Are Published Externally by Default<![CDATA[ ## Vulnerability Details **File Location**: `core.py:20-50, 259-265, 366-449` **Vulnerability Type**: Default external disclosure without explicit per-run consent **Risk Level**: High ### Complete Code Snippet ```python def __init__( self, whisper_model: str = "large-v2", transcribe_language: Optional[str] = None, analysis_types: Optional[List[str]] = None, output_dir: str = "./video-analysis", save_transcript: bool = True, config_path: Optional[str] = None, summary_style: Optional[SummaryStyle] = None, enable_screenshots: bool = True, publish_to_feishu: bool = True, feishu_space_id: Optional[str] = None, feishu_parent_node_token: Optional[str] = None, ): ... self.publish_to_feishu = publish_to_feishu self.feishu_space_id = feishu_space_id self.feishu_parent_node_token = feishu_parent_node_token ``` ```python output_files = self._save_results(video_info, transcript, analyses) feishu_publish = self._publish_to_feishu_if_needed( video_info=video_info, transcript=transcript, analyses=analyses, output_files=output_files, ) ``` ```python def _publish_to_feishu_if_needed( self, video_info: Dict[str, Any], transcript: str, analyses: Dict[str, str], output_files: Dict[str, str], ) -> Dict[str, Any]: """Publish all generated content to Feishu wiki doc when enabled.""" if not self.publish_to_feishu: return {"enabled": False, "success": False, "skipped": True} try: markdown_content = self._build_feishu_markdown( video_info=video_info, transcript=transcript, analyses=analyses, output_files=output_files, ) publisher = FeishuPublisher( space_id=self.feishu_space_id, parent_node_token=self.feishu_parent_node_token, config_path=self.config_path, ) return publisher.publish( video_title=video_info.get("title", "") ...[truncated 3600 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Change `publish_to_feishu` to `False` by default in all API and CLI entry points. 2. Require explicit per-run authorization before transmitting content. 3. Display the destination space, parent node, document title, and categories of content that will be uploaded. 4. Allow granular publication choices, such as summary only, excluding the transcript and local source path. 5. Warn users when local files or potentially sensitive content are selected. 6. Validate the destination and, where the Feishu API permits it, display or verify the resulting access policy. 7. Support redaction of secrets, personal data, and local paths before publication. 8. Record a local audit event containing the destination and publication time without logging credentials or document contents. ]]>

T08 · Insecure Dependencies

Error
Location
dependency_manager.py:9
Finding
Missing Dependencies Are Automatically Installed from an Unpinned Supply Chain<![CDATA[ ## Vulnerability Details **File Location**: `dependency_manager.py:9-19, 49-79, 97-111`; `requirements.txt:4-22` **Vulnerability Type**: Automatic runtime package installation without exact versions or integrity hashes **Risk Level**: High ### Complete Code Snippet ```python REQUIRED_PYTHON_PACKAGES = { "yt-dlp": "yt-dlp>=2024.0.0", "faster_whisper": "faster-whisper>=1.0.0", "modelscope": "modelscope>=1.0.0", "openai": "openai>=1.0.0", "tenacity": "tenacity>=8.0.0", } OPTIONAL_PYTHON_PACKAGES = { "opencc": "opencc-python-reimplemented", "anthropic": "anthropic>=0.18.0", "bilibili_api": "bilibili-api-python", } ``` ```python @staticmethod def install_package(package: str) -> bool: """Install a Python package.""" try: result = subprocess.run( [sys.executable, "-m", "pip", "install", package], capture_output=True, text=True, ) return result.returncode == 0 except Exception: return False @staticmethod def install_all_missing() -> bool: """Install all missing packages.""" status = DependencyManager.check_python_packages() missing = [ pkg for pkg in REQUIRED_PYTHON_PACKAGES.keys() if not status.get(pkg, False) ] if not missing: return True print(f"[INFO] Installing {len(missing)} packages...") for pkg in missing: print(f" - {pkg}") if not DependencyManager.install_package(REQUIRED_PYTHON_PACKAGES[pkg]): print(f" [ERROR] Failed: {pkg}") return False return True ``` ```python def check_and_install_dependencies() -> bool: """Check and install all dependencies. Returns True if ready.""" print("[INFO] Checking dependencies...") py_status = DependencyManager.check_python_packages() missing_py = [ pkg for pkg in REQUIRED_PYTHON_PACKAGES.keys() if not py_status.get(pkg, False) ] if missing_py: print(f"[WARN] {len(miss ...[truncated 1931 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove automatic package installation from normal execution. 2. Require dependencies to be installed during a controlled deployment step. 3. Generate a reviewed lockfile with exact versions for direct and transitive dependencies. 4. Use hash-verified installation, such as `pip install --require-hashes`. 5. Install dependencies in an isolated virtual environment or container with restricted privileges. 6. Configure a trusted internal package index and disable fallback to unapproved public indexes where appropriate. 7. Apply automated vulnerability and provenance scanning to dependency updates. 8. Fail safely with installation instructions when a dependency is missing instead of modifying the environment automatically. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
downloader.py:82
Finding
TLS Certificate Verification Is Disabled for Media and Subtitle Downloads<![CDATA[ ## Vulnerability Details **File Location**: `downloader.py:82-105, 119-143, 320-337` **Vulnerability Type**: Disabled TLS peer verification **Risk Level**: Medium ### Complete Code Snippet ```python def _download_audio(self, url: str) -> Tuple[str, dict]: """Download audio from online video.""" output_template = str(self.data_dir / "%(id)s.%(ext)s") ydl_opts = { "format": "bestaudio[ext=m4a]/bestaudio/best", "outtmpl": output_template, "postprocessors": [ { "key": "FFmpegExtractAudio", "preferredcodec": "mp3", "preferredquality": "64", } ], "noplaylist": True, "quiet": True, "no_warnings": True, "nocheckcertificate": True, "http_chunk_size": 10485760, } ``` ```python def _download_subtitles( self, url: str ) -> Tuple[Optional[str], Optional[List[Dict[str, Any]]], Optional[Dict[str, Any]]]: """Download subtitles (manual first, then auto captions) and parse text.""" output_template = str(self.data_dir / "%(id)s.%(ext)s") ... ydl_opts = { "skip_download": True, "writesubtitles": True, "writeautomaticsub": True, "subtitleslangs": sublangs, "subtitlesformat": "vtt/srt/best", "outtmpl": output_template, "noplaylist": True, "quiet": True, "no_warnings": True, "nocheckcertificate": True, "http_chunk_size": 10485760, } ``` ```python def _download_video(self, url: str) -> Tuple[str, dict]: """Download video file from online source.""" output_template = str(self.data_dir / "%(id)s.%(ext)s") ydl_opts = { "format": "bestvideo+bestaudio/best", "outtmpl": output_template, "merge_output_format": "mp4", "noplaylist": True, "quiet": True, "no_warnings": True, "nocheckcertificate": True, "http_chunk_size": 10485760, } ` ...[truncated 1364 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `nocheckcertificate=True` from every yt-dlp option set. 2. Use the operating system or an explicitly managed trusted certificate store. 3. Fail closed when certificate validation fails. 4. If a private certificate authority is required, configure its certificate explicitly rather than disabling verification globally. 5. Consider restricting accepted URL schemes to HTTPS for online sources. 6. Log certificate failures without exposing sensitive URL query values. 7. Add tests confirming that invalid and self-signed certificates are rejected. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
llm_processor.py:37
Finding
Untrusted Transcript Instructions Are Mixed Directly with LLM Control Instructions<![CDATA[ ## Vulnerability Details **File Location**: `llm_processor.py:37-76, 106-121`; `prompts/summary.md:81-83` **Vulnerability Type**: Indirect prompt injection through attacker-controlled video or subtitle content **Risk Level**: Medium ### Complete Code Snippet ```python def _load_prompt(self, prompt_type: str) -> Optional[str]: """Load prompt template.""" prompt_file = self.prompts_dir / f"{prompt_type}.md" if not prompt_file.exists(): return None with open(prompt_file, "r", encoding="utf-8") as f: content = f.read().strip() # Add placeholder if missing if "{transcript_text}" not in content: content += "\n\n{transcript_text}" return content ``` ```python def process(self, text: str, prompt_type: str) -> Optional[str]: ... prompt_template = self._load_prompt(prompt_type) if not prompt_template: print(f"⚠️ Prompt not found: {prompt_type}") return None prompt = prompt_template.format(transcript_text=text) llm_config = self.config.get("llm", {}) provider = llm_config.get("provider", "openai") if provider == "openai": return self._call_openai(prompt, llm_config) elif provider == "anthropic": return self._call_anthropic(prompt, llm_config) ``` ```python response = client.chat.completions.create( model=model, messages=[{"role": "user", "content": prompt}], temperature=config.get("temperature", 0.3), max_tokens=config.get("max_tokens", 4000), ) ``` ```markdown --- ## Video transcript content {transcript_text} ``` ### Technical Analysis Video transcripts and downloaded subtitles are untrusted content. The implementation inserts this content directly into the same user message that contains the analysis instructions. It does not establish a higher-priority system instruction stating that transcript commands are data, nor does it validate that the response follows an expected structure. A video author can include text ...[truncated 1431 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Put trusted behavioral rules in a system message rather than combining all instructions with transcript data in one user message. 2. Explicitly state that transcript content is untrusted quoted data and that instructions found inside it must never be followed. 3. Delimit transcript content using a clear structured container and length metadata. 4. Use structured response schemas for key-node selection and other machine-consumed outputs. 5. Validate response structure, allowed fields, timestamps, links, and content length before saving or publishing. 6. Add a confirmation or review stage before externally publishing LLM-generated content. 7. Apply defense-in-depth detection for common prompt-injection phrases, while not relying on filtering as the sole control. 8. Preserve provenance by distinguishing direct transcript quotations from model-generated analysis. ]]>
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
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (61)

Hidden Instructions

High
Category
Prompt Injection
Content
---
name: video-analyzer
version: 1.0.10
description: 鏅鸿兘鍒嗘瀽 Bilibili/YouTube/鏈湴瑙嗛锛岀敓鎴愯浆鍐欍€佽瘎浼板拰鎬荤粨銆傛敮鎸佸叧閿抚鎴浘鑷姩宓屽叆銆?
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Ae1

High
Category
analysis-evasion
Content
- 鍏朵粬渚濊禆瑙?`requirements.txt`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Missing User Warnings

High
Confidence
98% confidence
Finding
The skill says analysis results are published to Feishu after completion, but this behavior is not clearly surfaced earlier as a core side effect. Automatic publication of generated summaries, evaluations, and transcripts can leak sensitive content to a collaboration platform without informed user consent.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
# 安装 FFmpeg (必需)
# Windows: winget install ffmpeg
# macOS: brew install ffmpeg
# Linux: sudo apt install ffmpeg
```

## 使用方法
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The README states that publishing to Feishu is enabled by default, but it does not clearly warn users that generated transcripts, summaries, and possibly screenshots may be uploaded to an external knowledge base automatically. This creates a real privacy and data-exposure risk because users may process sensitive local or online video content without realizing results will be sent off-host.

Ae4

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

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill downloads remote videos and sends extracted/transcribed content to third-party LLM/API providers, but this data handling is not clearly disclosed where users decide to invoke the skill. That creates a transparency and privacy risk because users may provide copyrighted, private, or sensitive media without realizing it will be transmitted externally.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
The skill’s stated purpose is video analysis, but it additionally instructs automatic Feishu document creation and publication to an external platform. That expands the data flow beyond analysis into exfiltration/sharing of transcripts and summaries, which is risky because users may not expect their processed content to be published externally.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
This code automatically publishes the full transcript and generated analyses to Feishu whenever `publish_to_feishu` is enabled, but this file shows no explicit consent prompt, confirmation step, or visible disclosure before transmitting potentially sensitive content to an external collaboration platform. Because transcripts can contain confidential spoken information, links, screenshots, or model-generated summaries, silent publication creates a real privacy and data-leakage risk rather than a purely informational issue.

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Content
for pkg_name in {**REQUIRED_PYTHON_PACKAGES, **OPTIONAL_PYTHON_PACKAGES}:
            try:
                import_name = pkg_name.replace("-", "_").replace(".", "_")
                __import__(import_name)
                status[pkg_name] = True
            except ImportError:
                status[pkg_name] = False
Confidence
75% confidence
Finding
Dynamic __import__() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Context-Inappropriate Capability

Medium
Confidence
97% confidence
Finding
This dependency manager is explicitly designed to auto-install Python packages by spawning pip, which means the skill can modify the host environment and pull executable code from external package sources without a separate trusted installation phase. In agent or plugin contexts, that behavior is risky because it reduces operator control and creates a supply-chain execution path.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def install_package(package: str) -> bool:
        """Install a Python package."""
        try:
            result = subprocess.run(
                [sys.executable, "-m", "pip", "install", package],
                capture_output=True,
                text=True,
Confidence
95% confidence
Finding
The code automatically invokes pip in a subprocess to install packages at runtime. Although the command is passed as an argument list and does not use a shell, it still causes unprompted code acquisition and execution from package repositories, which expands the attack surface and can lead to supply-chain compromise or unexpected environment modification.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
guides = {
            "Windows": "winget install ffmpeg  # or: choco install ffmpeg",
            "Darwin": "brew install ffmpeg",
            "Linux": "sudo apt install ffmpeg  # Ubuntu/Debian\nsudo yum install ffmpeg  # CentOS",
        }

        return guides.get(os_name, "Download from https://ffmpeg.org/download.html")
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
guides = {
            "Windows": "winget install ffmpeg  # or: choco install ffmpeg",
            "Darwin": "brew install ffmpeg",
            "Linux": "sudo apt install ffmpeg  # Ubuntu/Debian\nsudo yum install ffmpeg  # CentOS",
        }

        return guides.get(os_name, "Download from https://ffmpeg.org/download.html")
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
guides = {
            "Windows": "winget install ffmpeg  # or: choco install ffmpeg",
            "Darwin": "brew install ffmpeg",
            "Linux": "sudo apt install ffmpeg  # Ubuntu/Debian\nsudo yum install ffmpeg  # CentOS",
        }

        return guides.get(os_name, "Download from https://ffmpeg.org/download.html")
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Context-Inappropriate Capability

Medium
Confidence
97% confidence
Finding
The top-level dependency check does more than assess readiness: it installs missing packages automatically. In a skill context this is more dangerous because simply invoking a check function can trigger network access, package installation, and code execution, violating least surprise and increasing exposure to malicious or compromised dependencies.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The downloader sends the provided URL and retrieves remote content via yt_dlp, which is a network operation involving user-supplied data. Although downloading is part of the functionality, these methods have no visible user-facing warning, logging, or docstring disclosure that online sources will be contacted and metadata/content fetched.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
This method creates an MP3 file in the data directory and runs ffmpeg as a subprocess, both of which are safety-relevant operations under the rule. The code has no confirmation prompt, logging/print statement, or explicit docstring warning that a new file will be written and an external binary executed.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
audio_path,
        ]

        result = subprocess.run(cmd, capture_output=True, check=True)

        return audio_path, {
            "title": video_file.stem,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The method downloads remote video content and saves it locally as an MP4, which affects both network/privacy and local filesystem state. While downloading is the intended behavior, there is no visible warning, log, or explicit disclosure in the code that this operation contacts external services and writes output files.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
]

        try:
            result = subprocess.run(cmd, capture_output=True, check=True, text=True)
            data = json.loads(result.stdout)
            duration = float(data.get("format", {}).get("duration", 0))
            return duration
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The public method and docstring imply additive publishing, but the implementation later clears all existing top-level document content before writing new blocks. This mismatch can cause unintended data loss when callers reasonably expect an append/update operation rather than destructive overwrite behavior.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The code deletes existing document blocks unconditionally before confirming whether converted replacement content can be inserted successfully. If conversion or insertion fails, the target Feishu document may be left empty or partially modified, creating avoidable integrity and availability loss for user content.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
This code sends raw transcript text to third-party LLM providers without any visible consent, minimization, or disclosure mechanism in the component itself. If transcripts contain sensitive, proprietary, or personal information, that data may be exposed to external services unexpectedly, creating privacy, compliance, and data-handling risk.

External Transmission

Medium
Category
Data Exfiltration
Content
or os.getenv("VIDEO_ANALYZER_API_KEY")
            or os.getenv("OPENAI_API_KEY")
        )
        base_url = config.get("base_url", "https://api.openai.com/v1")
        model = config.get("model", "gpt-4o-mini")

        if not api_key:
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.