Back to skill

Security audit

Bili Summary

Security checks for vulnerabilities and agentic risk

Overview

This skill has a clear video-summary purpose, but it should be reviewed because it can fetch arbitrary URLs and sends transcript text to Gemini with weak consent and credential handling.

Install only if you are comfortable with the skill making network requests and sending video subtitles or Whisper transcripts to Google Gemini for summarization. Use a restricted Gemini API key, prefer a temporary environment variable or a secret manager over adding the key to shell startup files, avoid private or internal URLs, and run the tool in an isolated environment with pinned dependencies where possible.

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

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/bili-summary.py:34
Finding

Unrestricted URL Processing Enables Server-Side Request Forgery

Content
View full analysis
tuple: """从视频URL获取aid和cid""" try: req = urllib.request.Request(url, headers={ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" }) with urllib.request.urlopen(req, timeout=10) as response: html = response.read().decode('utf-8') # 提取 __INITIAL_STATE__ match = re.search(r'window\.__INITIAL_STATE__=(.*?);\(function', html) if match: data = json.loads(match.group(1)) video_data = data.get("videoData", {}) return video_data.get("aid"), video_data.get("cid") # 备用方法:使用 yt-dlp cmd = [YT_DLP, "--dump-json", "--no-download", url] result = subprocess.run(cmd, capture_output=True, text=True) ``` The unrestricted argument is also passed to other network-capable operations: ```python def get_video_info(url: str) -> dict: """获取视频信息""" cmd = [YT_DLP, "--dump-json", "--no-download", url] result = subprocess.run(cmd, capture_output=True, text=True) ``` ```python parser.add_argument("url", help="B站视频URL") ``` ### Technical Analysis The positional argument is described as a Bilibili URL, but the implementation does not enforce that restriction. It performs no validation of: - The URL scheme - The destination hostname - Explicit ports or embedded credentials - The resolved IP address - Redirect destinations - Whether the destination is a loopback, private, link-local, or reserved address `urllib.request.urlopen()` directly opens the supplied URL and may follow redirects. The same value is also passed to the general-purpose `yt-dlp` executable, which supports mor ...[truncated 1823 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/bili-summary.py:224
Finding

Gemini API Key Is Exposed in a URL Query Parameter

Content
View full analysis
``` URL query strings are more likely than headers to be captured by HTTP infrastructure, proxy logs, tracing systems, exception telemetry, debugging output, or monitoring tools. HTTPS protects the request in transit but does not prevent the complete URL from being recorded at endpoints or trusted intermediaries. The request is sent to the documented Google Gemini endpoint, and no evidence shows intentional credential transmission to an unrelated party. The vulnerability is the unnecessary placement of the credential in a log-prone URL component. ### Attack Path 1. A user configures a valid `GEMINI_API_KEY` environment variable. 2. The summary action constructs a request URL containing the full key. 3. The request passes through local or remote logging, monitoring, proxy, tracing, or error-reporting infrastructure. 4. One of those systems records the complete URL. 5. A person or service with access to the retained logs extracts the API key. 6. The exposed key is used to submit unauthorized Gemini requests until it is revoked or restri ...[truncated 595 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:31
Finding

Unpinned Third-Party Dependency Installation Creates Supply-Chain Risk

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (17)

Tainted flow: 'req' from os.environ.get (line 251, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/bili-summary.py (reported line 46)May include surrounding context.

python
req = urllib.request.Request(url, headers={
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
        })
        with urllib.request.urlopen(req, timeout=10) as response:
            html = response.read().decode('utf-8')
        
        # 提取 __INITIAL_STATE__

Tainted flow: 'req' from os.environ.get (line 251, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/bili-summary.py (reported line 75)May include surrounding context.

python
req = urllib.request.Request(url, headers={
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
        })
        with urllib.request.urlopen(req, timeout=10) as response:
            html = response.read().decode('utf-8')
        
        # 提取 __INITIAL_STATE__

Tainted flow: 'req' from os.environ.get (line 251, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

The code fetches subtitle_url without validating the scheme or host before issuing an outbound request. Because subtitle_url comes from remote API data, a compromised or malicious upstream response could redirect the tool to arbitrary URLs, enabling SSRF-style access to internal services or unexpected local/network resources depending on runtime environment.

Content

Scanner excerpt · scripts/bili-summary.py (reported line 93)May include surrounding context.

python
req = urllib.request.Request(subtitle_url, headers={
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
        })
        with urllib.request.urlopen(req, timeout=10) as response:
            data = json.loads(response.read().decode('utf-8'))
            body = data.get("body", [])

Tainted flow: 'req' from os.environ.get (line 251, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
97% confidence
Finding

The script sends transcript/subtitle content and video metadata to an external Gemini API endpoint whenever GEMINI_API_KEY is configured. This is a real data-exposure issue because potentially sensitive or copyrighted content is transmitted off-box without an explicit consent gate at the call site, which is especially relevant in an agent skill context where users may not expect third-party sharing.

Content

Scanner excerpt · scripts/bili-summary.py (reported line 257)May include surrounding context.

python
headers={"Content-Type": "application/json"}
        )
        
        with urllib.request.urlopen(req, timeout=60) as response:
            result = json.loads(response.read().decode('utf-8'))
            return result.get("candidates", [{}])[0].get("content", {}).get("parts", [{}])[0].get("text", "总结失败")
    except Exception as e:

YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]

High
Category
YARA Match
Confidence
75% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

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

Gemini API Key

This skill uses Google Gemini 2.5 Flash for AI summarization.

Steps:

  1. Visit https://aistudio.google.com/app/apikey
  2. Sign in with your Google account
  3. Click "Create API Key"
  4. Copy the generated key

Pricing: Gemini 2.5 Flash has generous free tier (15 RPM, 1M TPM)

3. Set Environment Variable

bash
# Add to your ~/.bashrc or ~/.zshrc for permanent setup
echo 'export GEMINI_API_KEY="your-api-key-here"' >> ~/.bashrc
source ~/.bashrc

# Or set temporarily for current session
export GEMINI_API_KEY="your-api-key-here"

Quick Start

Full Workflow (Recommended)

bash
# Download audio, transcribe, and summarize in one command
uv run {baseDir}/scripts/bili-summary.py "https://www.bilibili.com/video/BV1xx411c7mu" --action summary

Other Actions

bash
# Get video info only
uv run {baseDir}/scripts/bili-summary.py "URL" --action info

# Download subtitle (if available)
uv run {baseDir}/scripts/bili-summary.py "URL" --action subti

Session Persistence

Medium
Category
Rogue Agent
Confidence
86% confidence
Finding

The instructions recommend persisting the Gemini API key in shell startup files such as ~/.bashrc or ~/.zshrc. Persisting secrets in broadly reused shell configuration increases exposure through accidental disclosure, shell-history-assisted inspection, backups, or unintended inheritance by unrelated processes.

Content

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

md
**Steps:**
1. Visit https://aistudio.google.com/app/apikey
2. Sign in with your Google account
3. Click "Create API Key"
4. Copy the generated key

**Pricing:** Gemini 2.5 Flash has generous free tier (15 RPM, 1M TPM)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill documents that it uses Gemini for summarization, but it does not prominently warn users that extracted subtitles or Whisper-generated transcripts may be transmitted to an external third-party AI service. This creates a real privacy and data-handling risk because users may assume processing is local when potentially sensitive audio-derived text is sent off-device.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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 140)May include surrounding context.

md
If you want to use other LLMs:

- **OpenAI GPT-4o** - https://api.openai.com/v1/chat/completions
- **Anthropic Claude** - https://api.anthropic.com/v1/messages
- **MiniMax** - https://api.minimax.chat/v1/text/chatcompletion_v2

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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 141)May include surrounding context.

md
If you want to use other LLMs:

- **OpenAI GPT-4o** - https://api.openai.com/v1/chat/completions
- **Anthropic Claude** - https://api.anthropic.com/v1/messages
- **MiniMax** - https://api.minimax.chat/v1/text/chatcompletion_v2

*Note: Current implementation only supports Gemini. PRs welcome for other providers.*

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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 142)May include surrounding context.

md
- **OpenAI GPT-4o** - https://api.openai.com/v1/chat/completions
- **Anthropic Claude** - https://api.anthropic.com/v1/messages
- **MiniMax** - https://api.minimax.chat/v1/text/chatcompletion_v2

*Note: Current implementation only supports Gemini. PRs welcome for other providers.*

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/bili-summary.py (reported line 58)May include surrounding context.

python
# 备用方法:使用 yt-dlp
        cmd = [YT_DLP, "--dump-json", "--no-download", url]
        result = subprocess.run(cmd, capture_output=True, text=True)
        if result.returncode == 0:
            info = json.loads(result.stdout)
            return info.get("aid"), info.get("cid")

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/bili-summary.py (reported line 111)May include surrounding context.

python
# 备用方法:使用 yt-dlp
        cmd = [YT_DLP, "--dump-json", "--no-download", url]
        result = subprocess.run(cmd, capture_output=True, text=True)
        if result.returncode == 0:
            info = json.loads(result.stdout)
            return info.get("aid"), info.get("cid")

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/bili-summary.py (reported line 156)May include surrounding context.

python
# 备用方法:使用 yt-dlp
        cmd = [YT_DLP, "--dump-json", "--no-download", url]
        result = subprocess.run(cmd, capture_output=True, text=True)
        if result.returncode == 0:
            info = json.loads(result.stdout)
            return info.get("aid"), info.get("cid")

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/bili-summary.py (reported line 272)May include surrounding context.

python
# 备用方法:使用 yt-dlp
        cmd = [YT_DLP, "--dump-json", "--no-download", url]
        result = subprocess.run(cmd, capture_output=True, text=True)
        if result.returncode == 0:
            info = json.loads(result.stdout)
            return info.get("aid"), info.get("cid")

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 · scripts/bili-summary.py (reported line 71)May include surrounding context.

python
def get_subtitle_url(aid: int, cid: int) -> str:
    """获取字幕URL"""
    try:
        url = f"https://api.bilibili.com/x/player/wbi/v2?aid={aid}&cid={cid}"
        req = urllib.request.Request(url, headers={
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
        })

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

This finding is valid: the summary path forwards large portions of subtitle or transcription text to an external LLM API with no explicit warning or confirmation in the execution flow. In a skill/agent setting, that increases privacy and compliance risk because users may believe processing is local while their content is actually being transmitted to a third party.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

The prompt hard-codes '请用中文回复', which enforces a specific output language regardless of user preference. This is a natural-language locale policy issue because the script does not offer a language choice or document a justified region-specific constraint.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.