Back to skill

Security audit

mcp-storyboard

Security checks for vulnerabilities and agentic risk

Overview

This skill can generate storyboard images, but it automatically rewrites ordinary person or character prompts with sexualized and demographic-specific content before sending them to a third-party API.

Install only if you are comfortable with prompts and generation parameters being sent to BizyAir using your API key, and review or remove the automatic model prompt suffix first. Avoid using this as-is for children, minors, sensitive stories, proprietary material, or ordinary character prompts because it can add sexualized adult-woman descriptors without a separate confirmation.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/bizyair_api.sh:101
Finding
Unsafe JSON Construction in the Shell API Fallback<![CDATA[ ## Vulnerability Details **File Location**: `scripts/bizyair_api.sh`, lines 101-130 **Vulnerability Type**: User-controlled JSON injection and missing numeric validation **Risk Level**: Medium ### Vulnerable Code ```bash # 解析参数 PROMPT="$1" RATIO="${2:-9:16}" BATCH_SIZE="${3:-4}" # 处理 prompt FINAL_PROMPT=$(process_prompt "$PROMPT") if [ "$FINAL_PROMPT" != "$PROMPT" ]; then echo "🤖 检测到模特关键词,已自动追加提示词" fi # 获取尺寸 read -r WIDTH HEIGHT <<< "$(get_size "$RATIO")" echo "📤 创建任务: prompt='$PROMPT', size=${WIDTH}x${HEIGHT}, batch=$BATCH_SIZE" # 创建任务 RESPONSE=$(curl -s -X POST "$API_ENDPOINT/create" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $BIZYAIR_API_KEY" \ -H "X-Bizyair-Task-Async: enable" \ --max-time 30 \ -d "{ \"web_app_id\": $WEB_APP_ID, \"suppress_preview_output\": true, \"input_values\": { \"107:BizyAirSiliconCloudLLMAPI.user_prompt\": \"$FINAL_PROMPT\", \"81:EmptySD3LatentImage.width\": $WIDTH, \"81:EmptySD3LatentImage.height\": $HEIGHT, \"81:EmptySD3LatentImage.batch_size\": $BATCH_SIZE } }") ``` ### Technical Analysis The fallback script builds JSON by directly interpolating user-controlled values into a double-quoted shell string. `FINAL_PROMPT` is inserted into a JSON string without JSON escaping, while `BATCH_SIZE` is inserted as a raw JSON value without verifying that it is an integer between 1 and 10. A prompt containing quotation marks, backslashes, newlines, or JSON delimiters can terminate or alter the intended `user_prompt` value. Depending on how the remote JSON parser handles injected or duplicate properties, this may modify other request fields or cause malformed requests. The batch argument can likewise contain arbitrary JSON syntax. More commonly, a user can submit a valid but excessively large numeric value because the shell fallback does not enforce the documented maximum batch size of 10. Shell ...[truncated 1380 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Construct the request with a JSON-aware tool instead of string interpolation. For example, use `jq` with `--arg` for strings and `--argjson` for validated numbers: ```bash if ! [[ "$BATCH_SIZE" =~ ^[0-9]+$ ]] || (( BATCH_SIZE < 1 || BATCH_SIZE > 10 )); then echo "Error: batch size must be an integer from 1 through 10" >&2 exit 1 fi PAYLOAD=$(jq -n \ --arg prompt "$FINAL_PROMPT" \ --argjson web_app_id "$WEB_APP_ID" \ --argjson width "$WIDTH" \ --argjson height "$HEIGHT" \ --argjson batch_size "$BATCH_SIZE" \ '{ web_app_id: $web_app_id, suppress_preview_output: true, input_values: { "107:BizyAirSiliconCloudLLMAPI.user_prompt": $prompt, "81:EmptySD3LatentImage.width": $width, "81:EmptySD3LatentImage.height": $height, "81:EmptySD3LatentImage.batch_size": $batch_size } }') ``` 2. Pass the resulting payload with `curl --data-binary "$PAYLOAD"`. 3. Enforce a batch range of 1 through 10 before making any network request. 4. Validate all numeric fields with strict integer syntax before using `--argjson`. 5. Use `curl --fail-with-body --show-error` and check the exit status so HTTP errors are not treated as valid API responses. 6. Add tests covering quotes, backslashes, control characters, Unicode, JSON delimiters, negative values, nonnumeric batches, and batches above 10. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/storyboard.py:240
Finding
Python Fallback Does Not Enforce Documented Resource Limits<![CDATA[ ## Vulnerability Details **File Location**: `scripts/storyboard.py`, lines 240-263 **Vulnerability Type**: Missing bounds validation for API resource parameters **Risk Level**: Medium ### Vulnerable Code ```python parser.add_argument("prompt", help="图片生成描述") parser.add_argument("--ratio", default="9:16", help="图片比例 (默认: 9:16)") parser.add_argument("--width", type=int, help="图片宽度(像素)") parser.add_argument("--height", type=int, help="图片高度(像素)") parser.add_argument("--batch", type=int, default=4, help="批次数量 (默认: 4)") parser.add_argument("--timeout", type=int, default=300, help="轮询超时时间(秒)") args = parser.parse_args() try: # 处理 prompt final_prompt = process_prompt(args.prompt) if final_prompt != args.prompt: print("🤖 检测到模特关键词,已自动追加提示词") # 解析尺寸 if args.width and args.height: width, height = args.width, args.height elif args.ratio in SIZE_MAP: width, height = SIZE_MAP[args.ratio] else: width, height = SIZE_MAP["9:16"] # 默认 # 创建任务 request_id = create_task(final_prompt, width, height, args.batch) ``` ### Technical Analysis Although `argparse` ensures that width, height, batch, and timeout values are integers, it does not impose any lower or upper bounds. Consequently, the Python fallback accepts negative, zero, or excessively large batch and dimension values. This differs from the MCP implementation, which limits batches to 1–10 and dimensions to 256–4096. Because the Skill documents automatic fallback behavior, weaker validation in the fallback path allows callers to bypass the controls applied by the primary MCP implementation. The Python implementation safely serializes its request through `requests.post(..., json=payload)`, so it is not affected by the shell fallback's JSON injection issue. The vulnerability here is specifically inconsistent and insufficient resource validation. ### Attack Path 1. An attacker requests image generation with an excessive batch size or dimensions ...[truncated 1004 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Apply the same limits used by the MCP implementation: - Batch size: 1 through 10. - Width and height: 256 through 4096. 2. Reject cases where only one of `--width` and `--height` is supplied. 3. Validate the timeout against a reasonable positive upper bound. 4. Use an `argparse` validator so invalid values are rejected before any network request: ```python def bounded_int(minimum: int, maximum: int): def parse(value: str) -> int: number = int(value) if not minimum <= number <= maximum: raise argparse.ArgumentTypeError( f"value must be between {minimum} and {maximum}" ) return number return parse parser.add_argument("--width", type=bounded_int(256, 4096)) parser.add_argument("--height", type=bounded_int(256, 4096)) parser.add_argument("--batch", type=bounded_int(1, 10), default=4) parser.add_argument("--timeout", type=bounded_int(1, 900), default=300) if (args.width is None) != (args.height is None): parser.error("--width and --height must be supplied together") ``` 5. Centralize validation rules or add parity tests so the MCP, Python, and shell paths enforce identical security constraints. 6. Add test cases for zero, negative, excessively large, and partially supplied dimension values. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (35)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill claims to be a storyboard/illustration assistant, but it silently rewrites prompts with sexualized body-focused text such as '大胸展示' and '完美身材', which is materially different from the declared behavior. Hidden prompt injection of this kind can cause unsafe or policy-violating image generation, surprise users, and create reputational, compliance, or abuse risks—especially in contexts involving portraits, minors, or general creative requests.

Vague Triggers

High
Confidence
95% confidence
Finding
The activation rule says the skill 'must' be used whenever the user mentions broad terms like '分镜', '场景图', or '绘本', which creates overbroad auto-invocation. Because this skill can transmit prompts to an external API and invoke shell/network capabilities, broad triggering increases the chance of unintended data disclosure or inappropriate execution on loosely related user requests.

Ae1

High
Category
analysis-evasion
Content
- **MCP 服务器实现**:`storyboard-mcp.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The script silently appends a highly sexualized and unrelated persona bundle to prompts whenever it detects generic people-related keywords. In a storyboard/children's illustration context, this materially changes user intent, can generate unsafe or policy-violating content, and creates a deceptive content-manipulation path that users did not request.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
if has_model_keyword(prompt):
        # 避免重复追加
        if "moweifei" not in prompt and "elegant woman" not in prompt:
            return prompt + MODEL_SUFFIX
    return prompt
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
if has_model_keyword(prompt):
        # 避免重复追加
        if "moweifei" not in prompt and "elegant woman" not in prompt:
            return prompt + MODEL_SUFFIX
    return prompt
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
if has_model_keyword(prompt):
        # 避免重复追加
        if "moweifei" not in prompt and "elegant woman" not in prompt:
            return prompt + MODEL_SUFFIX
    return prompt
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
if has_model_keyword(prompt):
        # 避免重复追加
        if "moweifei" not in prompt and "elegant woman" not in prompt:
            return prompt + MODEL_SUFFIX
    return prompt
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Natural-Language Policy Violations

High
Confidence
98% confidence
Finding
The automatic suffix hard-codes a specific ethnic/persona presentation ('20-year-old asian woman', '中式风格', '韩式写真') and appearance traits without user opt-in. This can materially alter outputs, impose identity/appearance stereotypes, and generate policy-sensitive content unrelated to the original request.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The README documents use of a third-party image-generation API and an API key, but it does not clearly disclose that user prompts and possibly generated content metadata will be transmitted to an external provider. In a skill that users may invoke with creative or sensitive story content, this omission can cause unintentional data disclosure and weakens informed consent.

External Transmission

Medium
Category
Data Exfiltration
Content
{
  "mcpServers": {
    "Storyboard-mcp": {
      "url": "https://api.bizyair.cn/w/v1/mcp/242",
      "headers": {
        "Authorization": "Bearer ${BIZYAIR_API_KEY}"
      }
Confidence
92% confidence
Finding
The skill is explicitly configured to send requests to an external endpoint with a bearer token, which means user prompts and associated generation requests leave the local environment. In this context, external transmission is expected for the feature to work, but it still creates a real confidentiality and supply-chain risk if users are not clearly warned or if the remote service is compromised.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill declares capabilities that include environment-variable access, outbound network access, and shell-based HTTP execution, but it does not constrain them with an explicit tool scope such as permissions or allowed-tools. This increases the blast radius if the skill is invoked unexpectedly or later modified, because the agent may use broader execution and exfiltration paths than users or reviewers can infer from the manifest.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill sends user prompts to an external image-generation API but does not prominently warn users that their text may leave the local environment. This can expose sensitive story content, personal data, or proprietary creative material to a third party without informed consent.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The manifest and instructions are written entirely in Chinese and direct mandatory use of the skill without offering a language choice or clarifying a region-specific constraint. This can constitute a language policy issue because the skill appears to assume a fixed language/locale rather than letting the user opt in or choose their preferred language.

External Transmission

Medium
Category
Data Exfiltration
Content
{
  "mcpServers": {
    "Storyboard-mcp": {
      "url": "https://api.bizyair.cn/w/v1/mcp/242",
      "headers": {
        "Authorization": "Bearer ${BIZYAIR_API_KEY}"
      }
Confidence
92% confidence
Finding
This skill is configured to send user prompts and related request data to an external third-party service at api.bizyair.cn, which is a real data egress path. Because the skill is explicitly invoked for storyboard, scene, and picture-book generation, users may provide sensitive story text, character descriptions, or proprietary creative content that will be transmitted off-platform along with an API credential. The external transmission is expected for functionality, but it is still a security-relevant vulnerability if data sharing is not clearly constrained, disclosed, and approved.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The comments describe automatic addition of a generic 'model prompt', but the implementation actually injects a narrow sexualized identity/style package. This mismatch is deceptive and increases risk because maintainers or users may believe the behavior is harmless while the code steers outputs toward sexualized content.

External Transmission

Medium
Category
Data Exfiltration
Content
echo "📤 创建任务: prompt='$PROMPT', size=${WIDTH}x${HEIGHT}, batch=$BATCH_SIZE"

# 创建任务
RESPONSE=$(curl -s -X POST "$API_ENDPOINT/create" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $BIZYAIR_API_KEY" \
    -H "X-Bizyair-Task-Async: enable" \
Confidence
86% confidence
Finding
This code sends user-supplied prompt content and generation parameters to an external service endpoint. In the context of a creative assistant, such prompts can contain unpublished story content or sensitive personal details, so the transmission is security-relevant and should be treated as an explicit data-exfiltration surface.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The script transmits the full user prompt to a third-party API without any explicit notice, consent flow, or data-minimization controls. Storyboard prompts may contain proprietary story details, personal data, or sensitive creative material, so undisclosed external transmission creates privacy and confidentiality risk.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The module docstring and all CLI help/output strings are written in Chinese, which imposes a specific language on users of the skill. There is no opt-in, locale selection, or documentation indicating that this tool is intentionally limited to a Chinese-speaking or region-specific audience.

External Transmission

Medium
Category
Data Exfiltration
Content
import argparse

# API 配置
BASE_URL = "https://api.bizyair.cn/w/v1/webapp/task/openapi"
WEB_APP_ID = 38223

# 模特提示词(当检测到人物相关关键词时自动追加)
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
import argparse

# API 配置
BASE_URL = "https://api.bizyair.cn/w/v1/webapp/task/openapi"
WEB_APP_ID = 38223

# 模特提示词(当检测到人物相关关键词时自动追加)
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
import argparse

# API 配置
BASE_URL = "https://api.bizyair.cn/w/v1/webapp/task/openapi"
WEB_APP_ID = 38223

# 模特提示词(当检测到人物相关关键词时自动追加)
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Context-Inappropriate Capability

Medium
Confidence
97% confidence
Finding
The skill automatically appends sexualized and body-focused prompt text whenever broad person-related keywords are detected, even for ordinary storyboard or illustration requests. This can coerce user intent, produce unwanted sexual content, and create safety, compliance, and reputational risk—especially because triggers like 'character' or 'person' are very broad in a storyboard tool.

External Transmission

Medium
Category
Data Exfiltration
Content
print(f"📤 创建任务: prompt='{prompt[:50]}...', size={width}x{height}, batch={batch_size}")

    response = requests.post(url, json=payload, headers=headers, timeout=30)
    response.raise_for_status()

    data = response.json()
Confidence
92% confidence
Finding
The skill transmits the full user prompt to a third-party external API, which is a genuine data egress point. In an agent setting, users may include sensitive story, customer, or proprietary content in prompts, and the code provides no consent prompt, redaction, or minimization beyond truncating console display.

Tainted flow: 'request_id' from requests.post (line 119, network input) → requests.get (network output)

Medium
Category
Data Flow
Content
last_progress_time = time.time()

        try:
            response = requests.get(
                url,
                params={"requestId": request_id},
                headers=headers,
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
storyboard-mcp.js:467