Back to skill

Security audit

Bilibili Helper

Security checks for vulnerabilities and agentic risk

Overview

This Bilibili content helper is mostly on-purpose, but its shell helper has unsafe input handling that could run local commands or read/write Markdown files outside its draft folder.

Install only if you are comfortable reviewing or fixing the shell helper first. Avoid passing untrusted values to the outline duration argument, avoid using draft names containing path characters, and know that draft text and command topics may be stored locally under the tool's data directory.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T01 · Skill Instruction Hijacking

Error
Location
scripts/bilibili.sh:118
Finding
Unconditional Third-Party Promotional Output Injection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/bilibili.sh`, lines 118-119 **Vulnerability Type**: Persistent output manipulation **Risk Level**: High ### Vulnerable Code ```python print("") print("Powered by BytesAgain | bytesagain.com") ``` ### Technical Analysis The embedded Python program unconditionally appends a third-party brand name and external domain to every response. This footer is not limited to the help or version output and cannot be disabled by the caller. Consequently, content produced through the script is modified to include unrelated promotional material. If an AI agent treats the command output as content intended for direct publication, the third-party attribution and URL can be propagated without the user explicitly requesting or approving them. The behavior does not execute remote code or transmit information to the domain, but it constitutes persistent output manipulation because it changes every generated result. ### Attack Path 1. A user or agent invokes any supported operation through `scripts/bilibili.sh`. 2. The embedded Python program generates the requested content. 3. Lines 118-119 append the third-party brand and domain unconditionally. 4. The caller consumes or republishes the complete command output. 5. The unrelated promotional material is included in the downstream response or publication. No attacker-supplied input is required because the output modification is hardcoded. ### Impact Assessment This issue does not grant operating-system privileges or provide access to local data. Its impact is limited to the integrity and trustworthiness of generated output: - Unrequested advertising may be incorporated into user-facing content. - AI agents may reproduce an external URL as though it were part of the requested result. - Automated workflows cannot obtain clean output without additional filtering. - Users may mistakenly interpret the promoted domain as necessary for the skill’s operation. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions Remove the unconditional promotional footer from normal command output: ```python # Do not append third-party promotional content here. ``` If attribution is legitimately required, restrict it to an explicit informational command such as `help`, `about`, or `version`. Alternatively, introduce an opt-in flag and keep machine-readable or generated content free of unrelated material by default. The documentation should clearly disclose any attribution that remains, and tests should verify that content-generation commands return only the content requested by the caller. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/script.sh:66
Finding
Shell Command Execution Through Unvalidated Arithmetic Input<![CDATA[ ## Vulnerability Details **File Location**: `scripts/script.sh`, lines 66-78 **Vulnerability Type**: Bash arithmetic-expression injection leading to command execution **Risk Level**: High ### Vulnerable Code ```bash cmd_outline() { local topic="${1:?用法: bilibili-helper outline <话题> [时长分钟]}" local dur="${2:-8}" echo " ═══ 视频脚本: $topic (${dur}分钟) ═══" echo "" echo " [0:00-0:15] 开场钩子" echo " → 「三秒定生死」: 冲击画面/问题/数据" echo "" echo " [0:15-0:40] 自我介绍+预告" echo " → 「大家好,今天聊$topic」" echo " → 预告内容要点(制造期待)" echo "" local seg=$(( (dur * 60 - 60) / 3 )) ``` ### Technical Analysis The `dur` variable is populated directly from the second command-line argument and is then evaluated inside Bash arithmetic expansion: ```bash $(( (dur * 60 - 60) / 3 )) ``` Bash arithmetic expansion does not merely parse decimal integer strings. It supports variable references, array subscripts, and nested shell expansions. Variable values used in arithmetic contexts can be recursively interpreted as arithmetic expressions. A crafted duration containing an array subscript with command substitution can therefore cause a shell command to run during evaluation. A representative payload is: ```bash 'x[$(touch /tmp/bilibili-outline-pwned)]' ``` When Bash evaluates `dur`, it interprets the supplied value as an arithmetic expression. Evaluation of the array subscript triggers the embedded command substitution. The arithmetic operation can subsequently fail under strict-shell settings, but the substituted command may already have executed. ### Attack Path 1. An attacker gains control over the duration argument supplied to the `outline` command. This can occur through direct local invocation or through an agent that forwards untrusted user input to the script. 2. The attacker invokes the script with a crafted arithmetic expression: ```bash ./scripts/script.sh outline demo 'x[$(touch /tmp/bilibili-outline-pwned)]' ``` 3 ...[truncated 1155 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Validate the duration as a bounded decimal integer before using it in arithmetic: ```bash cmd_outline() { local topic="${1:?Usage: bilibili-helper outline <topic> [duration-minutes]}" local dur="${2:-8}" if [[ ! "$dur" =~ ^[0-9]+$ ]]; then printf 'Invalid duration: a decimal integer is required.\n' >&2 return 2 fi if (( 10#$dur < 1 || 10#$dur > 120 )); then printf 'Invalid duration: value must be between 1 and 120 minutes.\n' >&2 return 2 fi local duration_number=$((10#$dur)) local seg=$(( (duration_number * 60 - 60) / 3 )) # Continue processing... } ``` The `10#` prefix forces decimal interpretation and prevents values with leading zeroes from being interpreted as octal. Additional hardening should include: - Treating all values passed to arithmetic expansion as untrusted until validated. - Keeping the permitted duration range narrow and appropriate to the application. - Adding regression tests with shell metacharacters, substitutions, array syntax, negative values, very large integers, and malformed numbers. - Avoiding invocation of the script with arguments derived from untrusted content unless each argument has been validated according to its expected type. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/script.sh:243
Finding
Draft Name Path Traversal Allows Filesystem Reads and Writes Outside the Draft Directory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/script.sh`, lines 243-248 **Vulnerability Type**: Path traversal in local draft storage **Risk Level**: Medium ### Vulnerable Code ```bash cmd_draft() { local action="${1:-list}" case "$action" in save) cat > "$DATA_DIR/drafts/${2:?}.md"; echo "已保存: $2" ;; list) ls -1 "$DATA_DIR/drafts/"*.md 2>/dev/null | xargs -I{} basename {} .md || echo "(空)" ;; show) [ -f "$DATA_DIR/drafts/${2:?}.md" ] && cat "$DATA_DIR/drafts/$2.md" || echo "找不到" ;; esac } ``` ### Technical Analysis The second argument is used directly as a filename under `$DATA_DIR/drafts`: ```bash "$DATA_DIR/drafts/${2:?}.md" ``` Quoting prevents word splitting and wildcard expansion, but it does not prevent filesystem traversal. A draft name containing `../` components can escape the intended drafts directory after path normalization. For example: ```text ../../../../tmp/exposed ``` is converted into a path resembling: ```text $DATA_DIR/drafts/../../../../tmp/exposed.md ``` The operating system resolves the parent-directory components before opening the file. The `save` operation can therefore truncate and overwrite a writable `.md` file outside the drafts directory, while `show` can disclose a readable `.md` file outside that directory. The `.md` suffix limits straightforward attacks to targets ending in `.md`, but it does not enforce confinement to the expected storage directory. ### Attack Path #### Arbitrary File Read Within Process Permissions 1. The attacker identifies a readable `.md` file and determines a traversal path relative to `$DATA_DIR/drafts`. 2. The attacker invokes: ```bash ./scripts/script.sh draft show '../../../../tmp/private' ``` 3. The script constructs a path ending in `/tmp/private.md`. 4. The `-f` check follows the resolved traversal path. 5. If the target exists and is readable, `cat` prints its contents. #### Arbitrary File Overwrite Within Process Perm ...[truncated 1371 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Restrict draft identifiers to a conservative filename allowlist and reject path separators, traversal sequences, empty names, and control characters: ```bash _validate_draft_name() { local name="$1" if [[ ! "$name" =~ ^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$ ]]; then printf 'Invalid draft name.\n' >&2 return 2 fi if [[ "$name" == "." || "$name" == ".." || "$name" == *".."* ]]; then printf 'Invalid draft name.\n' >&2 return 2 fi } ``` Use the validated name only after the check: ```bash cmd_draft() { local action="${1:-list}" local name case "$action" in save) name="${2:?Draft name required}" _validate_draft_name "$name" || return cat > "$DATA_DIR/drafts/$name.md" printf 'Saved: %s\n' "$name" ;; show) name="${2:?Draft name required}" _validate_draft_name "$name" || return if [[ -f "$DATA_DIR/drafts/$name.md" ]]; then cat -- "$DATA_DIR/drafts/$name.md" else printf 'Draft not found.\n' >&2 return 1 fi ;; esac } ``` For defense in depth: - Canonicalize both the drafts directory and target path and verify that the target remains beneath the canonical drafts directory. - Reject symbolic-link targets or open files using platform facilities that prevent symlink following where possible. - Create data directories with restrictive permissions, such as mode `0700`. - Create new draft files with restrictive permissions, such as mode `0600`. - Add tests for `../`, absolute paths, repeated separators, encoded separators, control characters, and symlink-based escape attempts. ]]>
Vulnerability Patterns
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (7)

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This Python skill emits user-facing titles, descriptions, scripts, help text, and labels exclusively in Chinese, which effectively forces a specific language for all users. The file does not provide any opt-in, language selection mechanism, or justification that the skill is intended only for a Chinese-language or region-specific context.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The draft save command writes arbitrary user-supplied content to disk without any user-facing notice, confirmation, or privacy disclosure. This can cause users to persist sensitive text unintentionally, especially if they believe the tool is only generating ephemeral output.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The _log function silently appends command names and user-provided arguments to a local history file. Because arguments may contain sensitive topics, personal data, or confidential draft subjects, undisclosed logging creates a privacy risk and may leak information to other local users or backups.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The script's user-facing strings are predominantly fixed in Chinese, including titles, labels, and guidance text, with no option to select another language or indication that the skill is intentionally limited to a Chinese-speaking audience. This creates a natural-language locale policy concern because the skill effectively forces a specific language without user opt-in.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
The skill's natural-language interface, help text, and output strings are presented only in Chinese, effectively forcing a specific language on users. The file does not indicate that the tool is region-specific or provide any language/locale selection.

Intent-Code Divergence

Low
Confidence
79% confidence
Finding
The user-facing help and module banner describe commands for idea generation, templates, and analytics, but do not disclose that invoking commands writes a history log and that drafts can be saved to disk. This is not merely omitted implementation detail for a shell helper, because the documentation frames the tool as an assistant while the code adds persistent local storage side effects.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
The markdown content is entirely in Chinese and presents usage guidance without indicating that the skill is intentionally limited to Chinese-speaking users or that alternative languages are available. Under the language/locale policy rule, this can be treated as a natural-language policy concern when no opt-in or justification is provided.

Static analysis

No suspicious patterns detected.