Back to skill

Security audit

Bilibili Video

Security checks for vulnerabilities and agentic risk

Overview

This skill appears to perform Bilibili subtitle and audio extraction, but it should be reviewed carefully because it stores Bilibili session cookies and can run an unverified local ASR shell script.

Install only if you are comfortable with this skill storing Bilibili session cookies locally and using them automatically. Prefer a sandboxed environment, verify or disable the external speech-to-text.sh fallback before use, monitor /tmp/openclaw/bilibili/ for retained transcripts/audio, and delete ~/.openclaw/workspace/.bilibili_cookies.json when you no longer need authenticated access.

Vulnerability Patterns
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • 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 (2)

T07 · Tool Hijacking and Spoofing

Warning
Location
scripts/bilibili_extract.py:316
Finding
Execution of an Unverified External Shell Script## Vulnerability Details **File Location**: `scripts/bilibili_extract.py:26, 273-274, 316-319` **Vulnerability Type**: Unverified execution of a mutable external tool **Risk Level**: Medium ### Vulnerable Code ```python ASR_SCRIPT = Path.home() / ".openclaw/workspace/scripts/speech-to-text.sh" ``` ```python if not ASR_SCRIPT.exists(): return None, None ``` ```python result = subprocess.run( ["bash", str(ASR_SCRIPT), str(wav_path)], capture_output=True, text=True, timeout=300 ) ``` ### Technical Analysis The extraction script invokes `speech-to-text.sh` from a mutable workspace location outside the audited package. The only validation performed before execution is an existence check. The code does not verify that the path is a regular file, reject symbolic links, validate file ownership or permissions, or compare the file against a trusted integrity hash. The use of an argument list rather than `shell=True` prevents direct command injection through `wav_path`, but it does not protect against replacement of the shell script itself. Anyone who can modify the workspace script path can determine the commands executed by the ASR fallback. Because the external script is not included in the audited project, its behavior and downstream network or command execution cannot be verified from this package. ### Attack Path 1. An attacker gains write access to `~/.openclaw/workspace/scripts/`, or causes `speech-to-text.sh` to be replaced with a symbolic link to an attacker-controlled file. 2. The attacker places arbitrary shell commands in the replacement script. 3. A user processes a Bilibili video for which CC and AI subtitles are unavailable. 4. The application enters the audio-transcription fallback. 5. Python invokes the attacker-controlled file through `bash`. 6. The commands execute with the same operating-system identity and permissions as the Agent process. ### Impact Assessment Success ...[truncated 512 chars]
Remediation
## Remediation Suggestions 1. Bundle the ASR implementation inside the reviewed Skill package rather than executing a mutable workspace script. 2. If an external executable must be supported, require the user to configure its path explicitly rather than relying on a fixed shared workspace location. 3. Resolve the path with `Path.resolve(strict=True)` and reject paths that escape an approved directory. 4. Use `lstat()` to reject symbolic links and require the target to be a regular file. 5. Verify that the file is owned by the expected operating-system account and is not writable by group or other users. 6. Pin and verify a cryptographic hash or signed manifest before every execution. 7. Run transcription in a restricted subprocess or container with minimum filesystem and network access. 8. Preserve argument-array invocation and continue avoiding `shell=True`. 9. Document the trust boundary and require explicit confirmation before first use of an external ASR program.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/bilibili_extract.py:298
Finding
Unbounded Remote Audio Downloads Can Exhaust Memory or Temporary Storage## Vulnerability Details **File Location**: `scripts/bilibili_extract.py:298-304 and 361-364` **Vulnerability Type**: Unbounded network response buffering **Risk Level**: Low ### Vulnerable Code ```python async with aiohttp.ClientSession(headers=headers) as session: async with session.get(audio_url) as resp: if resp.status != 200: print(f"[WARN] Audio download failed: HTTP {resp.status}") return None, None audio_data = await resp.read() audio_path.write_bytes(audio_data) ``` The audio-only path repeats the issue and does not validate the HTTP status: ```python async with aiohttp.ClientSession(headers=headers) as session: async with session.get(audio_url) as resp: audio_data = await resp.read() audio_path.write_bytes(audio_data) ``` ### Technical Analysis Both download paths call `resp.read()`, which buffers the complete remote response in process memory before writing it to disk. No maximum response size is configured, the `Content-Length` header is not checked, and no cumulative limit is enforced during transfer. The URLs normally originate from Bilibili API responses, which reduces direct attacker control but does not eliminate the risk from exceptionally large media, compromised or malformed API responses, redirects, or unexpected CDN behavior. The code also does not validate the final URL scheme or destination host after redirects. In the audio-only path, any HTTP response body is written as an audio file regardless of status. This can store an error document or other unexpected content and consume disk space without a successful-response check. ### Attack Path 1. A user requests extraction or audio download for a video whose returned audio resource is exceptionally large, malformed, or redirected to an oversized response. 2. The application follows the supplied media URL without a configured transfer-size limit. 3. `resp.read()` attemp ...[truncated 820 chars]
Remediation
## Remediation Suggestions 1. Stream response data in fixed-size chunks instead of using `resp.read()`. 2. Maintain a cumulative byte counter and abort the transfer when a configurable maximum audio size is exceeded. 3. Check `Content-Length` before downloading and reject responses above the permitted limit, while retaining the streaming limit because the header may be absent or inaccurate. 4. Require a successful HTTP status in both download paths by calling `resp.raise_for_status()` or explicitly accepting only expected status codes. 5. Restrict URLs to HTTPS and validate the initial and final redirect destinations against expected Bilibili or approved CDN hosts. 6. Configure connection, response-read, and total request timeouts. 7. Write to a newly created temporary file with restrictive permissions, then atomically rename it after a successful transfer. 8. Delete incomplete files after failures and implement retention or quota controls for downloaded audio. 9. Check available disk space before downloading and consider processing the stream without retaining the complete media file where practical.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
Findings (14)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The documented purpose centers on subtitle extraction and transcription, but the skill also instructs users to perform QR-code login, persist Bilibili cookies locally, and validate saved credentials. That mismatch is security-relevant because users may consent to a media-processing skill without realizing it handles account authentication material, increasing the risk of credential exposure or misuse.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill advertises and demonstrates capabilities requiring shell, network, file read, and file write access, but it does not declare any tool scope or permission boundary. This weakens least-privilege controls and makes it easier for the skill to be invoked with broader capabilities than users or the platform may expect, especially since it also writes transcripts and stores credentials locally.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The trigger phrases include broad terms like 'B站', 'bilibili', '看这个视频', and '视频内容', which can cause the skill to activate in situations where the user did not explicitly request downloading, transcription, or local storage. Over-broad invocation increases the chance of unintended network access, file writes, or login prompts in response to casual conversation.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The skill documents output paths and audio/transcript generation but does not clearly warn users that fetched media-derived content and possibly downloaded audio will be written to local storage. This can expose sensitive or copyrighted content on disk unexpectedly, particularly in shared environments or automated agent runs.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The notes explicitly instruct that key authentication cookies such as SESSDATA, bili_jct, and other account-linked values should be saved, but provide no warning about their sensitivity or guidance on secure storage. In this skill context, those cookies can grant authenticated access to a user's Bilibili account or purchased content, so documenting their collection and retention without safeguards increases the risk of credential theft or misuse.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
This code refreshes authentication cookies and writes updated credential material back to a file on disk. Although it prints status messages, there is no prior user-facing warning or confirmation that sensitive credentials will be persisted locally, which is a safety-relevant operation for a code file.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The helper unconditionally converts subtitle text from Traditional Chinese to Simplified Chinese when OpenCC is available. This is a language/locale behavior imposed by default, and the file provides no opt-in, opt-out, or locale selection for users who may want the original script preserved.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The function downloads video audio to a local file, converts it with ffmpeg, and invokes an external ASR shell script. While there are progress logs, the file performs file writes and subprocess execution on user-requested content without a clear advance warning in comments, docstrings, or interface text about these side effects.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# 转换为 wav(ASR 脚本可能需要)
        wav_path = OUTPUT_DIR / f"{bvid}_audio.wav"
        subprocess.run(
            ["ffmpeg", "-y", "-i", str(audio_path), "-ar", "16000", "-ac", "1", str(wav_path)],
            capture_output=True, timeout=120
        )
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
# 调用 ASR
        print("[INFO] 调用 ASR 转写...")
        result = subprocess.run(
            ["bash", str(ASR_SCRIPT), str(wav_path)],
            capture_output=True, text=True, timeout=300
        )
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Description-Behavior Mismatch

Medium
Confidence
98% confidence
Finding
The manifest description says the skill should work when users provide BV/AV/EP/SS identifiers, implying EP and SS are supported inputs. In code, SS inputs immediately abort and EP inputs are explicitly described as only limited and then also abort, so the actual behavior is narrower than the claimed capability.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The script persists active Bilibili authentication cookies, including session-related tokens, to a local file under the workspace home directory. Even though file mode 0600 is set, storing reusable account credentials expands the skill's capabilities beyond subtitle/audio extraction and creates a credential theft and account misuse risk if the workspace, host account, backups, or logs are exposed.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
The QR-code login flow obtains account credentials and saves them for later reuse, giving the skill a hidden authenticated-user capability that is not justified by the declared purpose of subtitle extraction, audio download, or transcription. In this context, the mismatch is security-relevant because users may scan a login QR code without expecting that durable account cookies will be retained and potentially used for broader actions available to that account.

Intent-Code Divergence

Low
Confidence
83% confidence
Finding
The docstring for parse_input says it returns only type values 'bv'|'ep'|'ss', but the implementation also recognizes AV identifiers and returns type 'av'. This is an active documentation mismatch about accepted inputs and returned values.

Static analysis

No suspicious patterns detected.