Back to skill

Security audit

VideoToText — subtitles & summary

Security checks for vulnerabilities and agentic risk

Overview

This skill has a coherent Bilibili subtitle and summarization purpose, but its code handles account cookies and user-supplied URLs in ways that could expose credentials or make unintended network requests.

Install only if you are comfortable reviewing or patching the network handling first. Treat SESSDATA, BILI_JCT, DEDEUSERID, and LLM API keys as secrets, avoid using a valuable Bilibili account, and prefer a local-only or trusted LLM endpoint until cookie host validation, redirect validation, and dependency pinning are addressed.

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

T09 · Insecure Skill Coding Practices

Error
Location
code/app/services/bilibili_subtitle.py:113
Finding

Bilibili authentication cookies may be disclosed to an unvalidated subtitle host

Content
View full analysis

Vulnerability Details

File Location: code/app/services/bilibili_subtitle.py:113-123, code/app/services/bilibili_subtitle.py:512-523, code/app/services/bilibili_subtitle.py:576-581, and code/app/services/bilibili_subtitle.py:604-608
Vulnerability Type: Cross-origin credential disclosure through an unvalidated remote URL
Risk Level: High

Vulnerable Code

python
for track in track_list:
    url = track.get("subtitle_url")
    if not url:
        continue
    subtitle_url = self._normalize_subtitle_url(url)
    try:
        response = self._request_with_retry(client, subtitle_url)
        payload = response.json()
    except Exception:
        continue

The same HTTP client is initialized with a default cookie header:

python
def _client_headers(self, cookie_header: Optional[str]) -> dict[str, str]:
    headers = {
        "User-Agent": (
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
            "(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
        ),
        "Referer": "https://www.bilibili.com/",
        "Accept": "application/json",
    }
    if cookie_header:
        headers["Cookie"] = cookie_header
    return headers

Requests are made without destination validation:

python
def _request_with_retry(
    self,
    client: httpx.Client,
    url: str,
    params: Optional[dict[str, Any]] = None,
) -> httpx.Response:
    last_error: Optional[Exception] = None
    for attempt in range(1, self.max_retries + 1):
        try:
            self._throttle()
            response = client.get(url, params=params)
            if response.status_code in {412, 429, 500, 502, 503, 504}:
                raise RuntimeError(f"HTTP {response.status_code}")
            response.raise_for_status()
            return response
        except Exception as exc:
            last_error = exc
            if at
...[truncated 2546 chars]
Remediation
View remediation

Remediation Suggestions

  1. Use separate HTTP clients for authenticated Bilibili API requests and subtitle downloads.
  2. Never configure the Bilibili cookie as a default header on the subtitle-download client.
  3. Attach cookies per request only after confirming that the destination is an explicitly approved Bilibili host.
  4. Parse every subtitle URL and require:
    • The https scheme.
    • An exact hostname or approved suffix from a narrowly defined allowlist.
    • No embedded username or password.
    • An approved port, normally 443.
  5. Reject IP-literal destinations and hosts that resolve to loopback, link-local, private, reserved, or multicast addresses.
  6. If redirects are permitted, validate every redirect target before following it and strip authentication headers on any origin change.
  7. Add tests proving that a subtitle URL on an unapproved host never receives a Cookie header.
  8. Consider initially requesting subtitles without authentication and adding narrowly scoped authentication only where the approved Bilibili endpoint requires it.

T09 · Insecure Skill Coding Practices

Warning
Location
code/app/utils/url_tools.py:7
Finding

Weak short-link validation permits SSRF through attacker-controlled hosts and redirects

Content
View full analysis

Vulnerability Details

File Location: code/app/utils/url_tools.py:7-15
Vulnerability Type: Server-Side Request Forgery
Risk Level: Medium

Vulnerable Code

python
def expand_short_url(url: str, timeout_seconds: int = 20) -> str:
    parsed = urlparse(url)
    if "b23.tv" not in parsed.netloc.lower():
        return url
    try:
        with httpx.Client(timeout=timeout_seconds, follow_redirects=True) as client:
            response = client.get(url)
            return str(response.url)
    except Exception as exc:
        raise AppError(ErrorCodes.INVALID_URL, f"Short-link expansion failed: {exc}", 400) from exc

Technical Analysis

The function attempts to restrict outbound requests to Bilibili's b23.tv short-link service, but it uses a substring check against netloc. This accepts unrelated attacker-controlled hosts such as:

text
b23.tv.attacker.example
attacker-b23.tv.example

The client also enables automatic redirects. Neither the initial destination nor subsequent redirect destinations are checked for loopback, private, link-local, reserved, or cloud metadata addresses.

As a result, a caller able to provide a URL can cause the application to connect to an attacker-controlled server and follow redirects to internal services reachable from the host running the Skill.

Attack Path

  1. An attacker supplies a URL such as https://b23.tv.attacker.example/path.
  2. The substring check succeeds because the attacker-controlled network location contains b23.tv.
  3. The Skill makes a server-side request to the attacker's host.
  4. The attacker responds with an HTTP redirect to an internal target, such as a loopback service, private-network address, or cloud metadata endpoint.
  5. Because follow_redirects=True, httpx follows the redirect without destination validation.
  6. The attacker may infer reachability or behavior through the final URL, response timing, ...[truncated 649 chars]
Remediation
View remediation

Remediation Suggestions

  1. Validate parsed.hostname rather than searching parsed.netloc for a substring.
  2. Require the hostname to be exactly b23.tv, or use a narrowly defined explicit allowlist if approved subdomains are necessary.
  3. Require HTTPS and reject URLs containing user information or unexpected ports.
  4. Disable automatic redirects and process redirects manually.
  5. Validate every redirect destination using the same hostname, scheme, port, and IP-address policy.
  6. Resolve destination hosts and reject loopback, private, link-local, reserved, multicast, and unspecified address ranges for both IPv4 and IPv6.
  7. Revalidate after DNS resolution and immediately before connection to reduce DNS rebinding exposure.
  8. Set a small redirect limit and retain the existing timeout.
  9. Add regression tests for deceptive hostnames, credentials in URLs, alternate ports, IPv6 literals, private addresses, and redirects to internal destinations.

T08 · Insecure Dependencies

Note
Location
requirements-code.txt:2
Finding

Open-ended dependency versions create non-reproducible and unsafe installations

Content
View full analysis

Vulnerability Details

File Location: requirements-code.txt:2-5
Vulnerability Type: Unpinned third-party dependencies
Risk Level: Low

Vulnerable Code

text
httpx>=0.27.0
pydantic>=2.0.0
pydantic-settings>=2.0.0
yt-dlp>=2024.0.0

The documented installation process executes:

bash
pip install -r requirements-code.txt

Technical Analysis

Every dependency uses an open-ended lower-bound constraint. A future installation can therefore retrieve package versions that did not exist when the Skill was audited and that have not been reviewed for compatibility or security.

Python package installation may execute package build logic, and installed packages execute with the privileges of the user running the Skill. The absence of exact pins, a lock file, and package hashes prevents reproducible verification of the installed artifacts.

The reviewed package names correspond to expected dependencies, and no evidence of typosquatting or an intentionally malicious package was found. The issue is the unrestricted future dependency selection and lack of integrity controls.

Attack Path

  1. A user follows the documented pip install command at a later date.
  2. The package resolver selects newer releases satisfying the open-ended constraints.
  3. A selected release contains a compromised artifact, malicious installation behavior, a newly introduced vulnerability, or an incompatible behavioral change.
  4. Installation or subsequent import executes the dependency with the privileges of the user running the command or Skill.
  5. The compromised dependency can access data and resources available to that process, including environment variables and the Skill's .env configuration.

Impact Assessment

A compromised dependency could execute arbitrary code with the privileges of the installing or running user. That scope could include reading Bilibili session cookies and LLM API k ...[truncated 200 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin every direct dependency to a reviewed exact version.
  2. Generate and commit a lock file that includes resolved transitive dependencies.
  3. Use hash-verified installation, such as a requirements file generated with hashes and installed using pip --require-hashes.
  4. Download packages only from an approved package index over HTTPS.
  5. Perform dependency updates through a controlled review process with automated vulnerability scanning and regression testing.
  6. Install dependencies in an isolated virtual environment using a non-privileged account.
  7. Consider separating build and runtime environments and using prebuilt, verified artifacts where practical.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (40)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The description claims substantial functionality around Bilibili link parsing, subtitle extraction, authentication/cookie handling, subtitle validation, and LLM-based summarization. However, the provided code chunk is just an empty app/init.py file and does not implement any of these behaviors. This is therefore a material description-versus-code mismatch: the declared primary purpose is not represented by the supplied code.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description promises substantial functionality related to Bilibili subtitle retrieval and LLM-based summarization, but the supplied code chunk shows no implementation at all. Because there is no code behavior matching the declared primary purpose, the description is not accurately represented by this code chunk. There are no undeclared capabilities present; the mismatch is that the actual code is effectively empty while the description claims significant features.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 75)May include surrounding context.

md
将本目录 **`videototext` 整夹** 打成 zip(含 `SKILL.md`、`reference.md`、`code/`、`requirements-code.txt`)。解压后:

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 77)May include surrounding context.

md
将本目录 **`videototext` 整夹** 打成 zip(含 `SKILL.md`、`reference.md`、`code/`、`requirements-code.txt`)。解压后:

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 78)May include surrounding context.

md
将本目录 **`videototext` 整夹** 打成 zip(含 `SKILL.md`、`reference.md`、`code/`、`requirements-code.txt`)。解压后:

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 75)May include surrounding context.

md
将本目录 **`videototext` 整夹** 打成 zip(含 `SKILL.md`、`reference.md`、`code/`、`requirements-code.txt`)。解压后:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · code/app/core/settings.py (reported line 13)May include surrounding context.

python
_PROJECT_ROOT = _this_file.parents[3]
else:
    _PROJECT_ROOT = _this_file.parents[2]
_ENV_FILE = _PROJECT_ROOT / ".env"


class Settings(BaseSettings):

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · code/app/core/settings.py (reported line 194)May include surrounding context.

python
_PROJECT_ROOT = _this_file.parents[3]
else:
    _PROJECT_ROOT = _this_file.parents[2]
_ENV_FILE = _PROJECT_ROOT / ".env"


class Settings(BaseSettings):

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · code/app/core/settings.py (reported line 196)May include surrounding context.

python
bullet = "\n".join([f"- {x}" for x in picks[:6]])
        summary = (
            f"本段围绕「{title or '该视频'}」展开,要点见上。"
            f"(本地回退摘要,目标约 {max_chars} 字;可在 .env 配置 SUMMARY_LLM_* 调用大模型。)"
        )
        return f"{bullet}\n\n{summary}"

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · code/app/services/summary.py (reported line 190)May include surrounding context.

python
bullet = "\n".join([f"- {x}" for x in picks[:6]])
        summary = (
            f"本段围绕「{title or '该视频'}」展开,要点见上。"
            f"(本地回退摘要,目标约 {max_chars} 字;可在 .env 配置 SUMMARY_LLM_* 调用大模型。)"
        )
        return f"{bullet}\n\n{summary}"

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill clearly describes capabilities that use network access and sensitive environment-provided credentials, but it does not declare any explicit tool scope or permission boundaries. That omission increases the chance an agent or operator will invoke the skill without understanding that it can make external requests and consume secrets such as Bilibili cookies and LLM API keys.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation instructs use of authentication cookies, including SESSDATA and related identifiers, and notes they are sent in request headers, but it does not provide a strong privacy/security warning about credential sensitivity or handling requirements. This can lead users or agents to paste high-value session tokens into insecure contexts or transmit them more broadly than intended.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The summary section explains that transcript text is sent to an OpenAI-compatible chat completions endpoint, but it does not clearly warn users that potentially sensitive subtitle/content data may be transmitted to a configurable third-party service. Without a clear notice and consent boundary, users may unknowingly export content outside their local environment.

Content

No source excerpt is available for this finding.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The configuration defaults local_asr_language to zh and sets an initial prompt instructing the model to write in simplified Chinese. This is a natural-language locale policy constraint embedded in code, and the file does not indicate any user choice or opt-in for this forced language/output format.

Content

No source excerpt is available for this finding.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest describes guidance for pulling Bilibili official subtitles and generating Chinese summaries, with troubleshooting around subtitle access and cookies. This file also implements extraction of a direct best-audio URL for ASR use, which is a broader media-acquisition capability not described in the stated skill purpose.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The request headers hard-code Accept-Language: zh-CN,zh;q=0.9, which forces a specific language/locale for fetched content. The file does not offer any user choice or documented justification for this locale restriction, so it violates the language/locale policy criteria.

Content

No source excerpt is available for this finding.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 42)May include surrounding context.

md
return headers

    def _fetch_view(self, client: httpx.Client, bvid: str) -> dict[str, Any]:
        resp = self._request_with_retry(client, "https://api.bilibili.com/x/web-interface/view", params={"bvid": bvid})
        data = resp.json()
        if data.get("code") != 0:
            raise RuntimeError(f"view API code={data.get('code')} message={data.get('message')}")

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 43)May include surrounding context.

md
return headers

    def _fetch_view(self, client: httpx.Client, bvid: str) -> dict[str, Any]:
        resp = self._request_with_retry(client, "https://api.bilibili.com/x/web-interface/view", params={"bvid": bvid})
        data = resp.json()
        if data.get("code") != 0:
            raise RuntimeError(f"view API code={data.get('code')} message={data.get('message')}")

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 44)May include surrounding context.

md
return headers

    def _fetch_view(self, client: httpx.Client, bvid: str) -> dict[str, Any]:
        resp = self._request_with_retry(client, "https://api.bilibili.com/x/web-interface/view", params={"bvid": bvid})
        data = resp.json()
        if data.get("code") != 0:
            raise RuntimeError(f"view API code={data.get('code')} message={data.get('message')}")

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · code/app/services/bilibili_subtitle.py (reported line 526)May include surrounding context.

python
return headers

    def _fetch_view(self, client: httpx.Client, bvid: str) -> dict[str, Any]:
        resp = self._request_with_retry(client, "https://api.bilibili.com/x/web-interface/view", params={"bvid": bvid})
        data = resp.json()
        if data.get("code") != 0:
            raise RuntimeError(f"view API code={data.get('code')} message={data.get('message')}")

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · code/app/services/bilibili_subtitle.py (reported line 554)May include surrounding context.

python
return headers

    def _fetch_view(self, client: httpx.Client, bvid: str) -> dict[str, Any]:
        resp = self._request_with_retry(client, "https://api.bilibili.com/x/web-interface/view", params={"bvid": bvid})
        data = resp.json()
        if data.get("code") != 0:
            raise RuntimeError(f"view API code={data.get('code')} message={data.get('message')}")

Static analysis

No suspicious patterns detected.