Back to skill

Security audit

公众号封面 & AI 配图

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its WeChat article image-generation purpose, but it needs review because it can send article prompts and an API key to a configurable endpoint without enforcing HTTPS.

Install only in a dedicated article workspace, use a restricted image-model API key, and configure only trusted HTTPS image endpoints. Avoid using account-wide master keys, and review any prior-draft or product-image directories the skill can read.

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

Error
Location
scripts/image_create.py:530
Finding
API credentials and article content can be transmitted over plaintext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `scripts/image_create.py`, lines 530–607 **Vulnerability Type**: Authenticated requests over an unrestricted URL scheme **Risk Level**: High ### Vulnerable Code ```python b = model_cfg["base_url"].rstrip("/") bl = b.lower() if api_type == "volcengine": url = b if "/api/v3/images/generations" in bl else f"{b}/api/v3/images/generations" elif api_type == "openai": if "/v1/chat/completions" in bl: url = b elif "/v1/images/generations" in bl: url = b else: _err( "image_model.base_url must contain the complete endpoint path." ) use_chat = "/v1/chat/completions" in url.lower() sent_aspect = None if use_chat: if aspect and _supports_image_config(model_cfg): sent_aspect = _nearest_supported_aspect(aspect) body = { "model": model_cfg["model"], "messages": [{"role": "user", "content": prompt}], } else: body = { "model": model_cfg["model"], "prompt": prompt, "n": 1, "size": size or model_cfg["default_size"], "quality": quality or model_cfg["default_quality"], "response_format": "b64_json", } data = json.dumps(body, ensure_ascii=False).encode("utf-8") req = urllib.request.Request( url, data=data, headers={ "Content-Type": "application/json", "Authorization": f"Bearer {model_cfg['api_key']}", }, ) try: with urllib.request.urlopen(req, timeout=120) as resp: result = json.loads(resp.read()) except urllib.error.HTTPError as e: error_body = e.read().decode("utf-8", errors="replace") _err(_format_api_failure("API call failed", e.code, error_body)) except (urllib.error.URLError, TimeoutError) as e: _fail_url(e, "connecting to image-generation API") ``` The same underlying issue also affects authenticated request construction for Gemini and Qwen endpoints around lines 628–662 and 696–730. ### Technical Analysis The co ...[truncated 1991 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse every API endpoint before constructing an authenticated request: ```python parsed = urllib.parse.urlparse(url) if parsed.scheme != "https": _err("Remote image-model endpoints must use HTTPS") ``` 2. If local development endpoints are necessary, permit plaintext HTTP only through an explicit opt-in and only for loopback addresses: ```python allow_local_http = config.get("allow_local_http", False) if parsed.scheme == "http": if not allow_local_http or parsed.hostname not in {"127.0.0.1", "::1", "localhost"}: _err("Plaintext HTTP is not permitted") ``` 3. Apply the same validation consistently to OpenAI-compatible, Volcengine, Gemini, Qwen, and asynchronous polling URLs. 4. Reject URLs containing embedded user information, malformed hosts, or unsupported schemes. 5. Recommend provider-specific, narrowly scoped API keys with independent quotas and billing limits. 6. Document that remote endpoints must use valid TLS and that users should not disable certificate verification. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/image_create.py:56
Finding
Image-download SSRF filtering is bypassable through redirects or DNS rebinding<![CDATA[ ## Vulnerability Details **File Location**: `scripts/image_create.py`, lines 56–92 **Vulnerability Type**: Incomplete SSRF protection with redirect and DNS time-of-check/time-of-use weaknesses **Risk Level**: Medium ### Vulnerable Code ```python def _is_safe_download_url(url: str) -> tuple[bool, str]: try: parsed = urllib.parse.urlparse(url) except Exception as e: return False, f"URL parsing failed: {e}" if parsed.scheme not in ("http", "https"): return False, f"Only HTTP/HTTPS is allowed: {parsed.scheme}://" hostname = parsed.hostname if not hostname: return False, "URL has no hostname" try: addrinfo = socket.getaddrinfo(hostname, None) ips = {info[4][0] for info in addrinfo} except Exception as e: return False, f"Unable to resolve hostname {hostname}: {e}" for ip_str in ips: try: ip = ipaddress.ip_address(ip_str) except ValueError: return False, f"Invalid IP: {ip_str}" if ( ip.is_loopback or ip.is_private or ip.is_link_local or ip.is_unspecified or ip.is_reserved or ip.is_multicast ): return False, f"Private or reserved address rejected: {hostname} -> {ip}" return True, "" def _safe_urlopen_download(url: str, timeout: int = 60): ok, reason = _is_safe_download_url(url) if not ok: raise urllib.error.URLError(f"SSRF protection rejected URL: {reason}") return urllib.request.urlopen(url, timeout=timeout) ``` This helper is used for model-supplied image URLs at lines 447, 476, 488, 504, 515, 757, and 772. ### Technical Analysis The script resolves the hostname during validation and checks the resulting addresses against private, loopback, link-local, reserved, unspecified, and multicast ranges. However, it then calls `urllib.request.urlopen()` using the original hostname. This creates two secur ...[truncated 2646 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Disable automatic redirect following for image downloads. 2. If redirects are required, process them manually and apply the full URL and address validation to every redirect target. Set a small redirect limit. 3. Resolve the destination once, retain the validated IP address, and ensure that the connection is made to that exact address while preserving the intended HTTP Host header and TLS server name. 4. Verify the connected peer address after connection and reject it if it belongs to a private, loopback, link-local, reserved, unspecified, multicast, or otherwise non-public range. 5. Apply equivalent checks to both IPv4 and IPv6 addresses and reject ambiguous or mixed resolution results. 6. Restrict image downloads further by enforcing: - Expected image MIME types. - Recognized image file signatures. - A maximum response size. - A maximum timeout. - A maximum redirect count. 7. Where supported by the model provider, prefer inline base64 image responses instead of retrieving arbitrary provider-supplied URLs. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (37)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
There is a clear description-behavior mismatch. The declared purpose promises AI-generated cover and illustration creation for公众号 articles, including automatic style matching and multiple design options. The supplied code only manages local filesystem content: it ensures an imgs/ directory exists, enumerates uploaded image files, selects or defaults a single cover image, and writes a markdown template for human completion. This is an image-organization/preparation helper, not an AI image synthesis or illustration generation tool. No model calls, prompt construction, image generation APIs, or article-content-based style selection appear in the code.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
if not isinstance(meta, dict):
                meta = {}
            prompt = parts[2].strip()
            return prompt, meta

    return text.strip(), {}
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Lp3

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding
The skill explicitly describes capabilities to read and write repository files and send prompts plus an API key to a user-configured external endpoint, but it does not declare any explicit tool scope such as permissions or allowed-tools. That creates an avoidable trust gap: an agent/runtime may permit broader filesystem or network access than users expect, increasing the chance of unintended data exposure or unsafe execution in a prompt-driven workflow.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The trigger phrases are very broad everyday terms like '封面', '配图', and '生成图片', which can cause the skill to activate in contexts where the user did not intend to invoke this specific workflow. In a skill that reads local article files, writes outputs, and sends prompt content to an external image endpoint, overbroad routing can lead to accidental data processing or external disclosure of article content.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The instruction states that any text appearing in images must be Chinese, which forces a specific language choice. The file does not indicate that the user can opt into another language or that the restriction is a documented region-specific requirement, so this is a natural-language locale policy violation.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The README presents all instructional content in Chinese and does not indicate that the skill is region-specific or that users may choose another language. Under the language/locale policy, forcing a specific language without user opt-in is a natural-language policy concern.

Natural-Language Policy Violations

Medium
Confidence
82% confidence
Finding
The instruction "画面中不出现任何文字、字母或数字" is a natural-language constraint embedded in the file and is written in a specific language without any opt-in or explanation. Under the policy rule, forcing a language/locale-specific instruction without user choice can be a policy concern when no justification or alternative is provided.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
Line L6 contains a Chinese-only instruction, which imposes a specific language/locale constraint in the skill content without any opt-in or alternative. This matches the policy category for language or locale restrictions expressed in natural language.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
Line L6 contains a Chinese-only instruction about the generated image content, indicating a language/locale-specific requirement embedded in the skill text. There is no accompanying user choice or justification that this skill is intentionally region- or language-specific, so it may violate the language/locale policy.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
Line L6 contains a natural-language instruction written only in Chinese, while the rest of the file is in English. This creates an implicit language constraint without offering the user a language or locale choice, which matches the policy category for forced language/locale behavior.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
Line L6 contains a Chinese-only instruction requiring that no text, letters, or numbers appear in the image. This introduces a language-specific directive in the skill content without any opt-in, alternative locale, or documented justification for using Chinese.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
Line L6 is written in Chinese and imposes a language-specific instruction for the generated content. Under the policy, forcing a specific language or locale without user opt-in can be a natural-language policy violation unless the locale constraint is explicitly justified.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
Line L6 contains a Chinese-only instruction and the file provides no indication that the locale is optional, user-selected, or justified by a region-specific purpose. This creates a natural-language locale constraint without opt-in, which matches the language policy violation category.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The instructions require cover titles of 4–7 Chinese characters and provide only Chinese copy examples such as 「规矩一次填清楚」 and 「周报太淡了」. This imposes a specific language/locale on outputs without user opt-in or a stated region-specific justification, which matches the language-policy violation criterion.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The entire skill description is written in Chinese and does not mention any user opt-in, language selection, or region-specific constraint. Under the stated policy, forcing a specific language without user choice is a natural-language policy violation.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The content repeatedly specifies that the generated text must be in Chinese, including '每格两行极简中文' and layout requirements for the title text. This is a natural-language locale restriction, and the file does not indicate user opt-in or a documented region-specific reason for forcing Chinese output.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The entire skill specification is written only in Chinese and defines output conventions such as '默认不加字', with no indication that users may choose another language or locale. Under the policy, a skill that imposes a specific language without opt-in is a natural-language policy violation unless the locale restriction is clearly documented and justified.

Natural-Language Policy Violations

Medium
Confidence
84% confidence
Finding
The entire skill specification is written as a Chinese-only template and includes mandatory textual requirements like '必须有' for the copy, but it does not offer any language or locale choice to the user. Under the policy, forcing a specific language without user opt-in can be a natural-language policy violation unless the locale constraint is explicitly justified.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The instruction says the annotation text 'must' be in Chinese, which imposes a fixed language requirement in natural-language content. This is a locale/language policy concern because the file does not provide any opt-in, fallback, or justification for restricting output to Chinese.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
This markdown file presents all instructions in Chinese and does not indicate that the user can choose another language or that the skill is intentionally limited to a Chinese-language audience. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation.

Context-Inappropriate Capability

Medium
Confidence
84% confidence
Finding
The document explicitly instructs enumerating prior `drafts/` directories and running a shell pipeline to read `article.yaml` metadata from other workspaces. Even though the goal is style consistency, this expands the skill from local image-prompt derivation into cross-directory inspection, which can expose unrelated draft content or metadata and normalizes shell-based file access beyond the minimum required scope.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
Lines L005-L009 require that all text appearing in images must be Chinese, and explicitly discourage alternatives such as English. This is a natural-language locale policy constraint that forces a specific language without presenting user choice or stating a region-specific compliance reason.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
Line L049 states that all image text must be in Chinese and instructs authors to write the exact Chinese wording in the prompt. This enforces a single language policy without opt-in and is not framed as a clearly justified regional constraint.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The entire skill specification is written as a prescriptive template in Chinese and does not offer any user language or locale choice. Under the stated policy, forcing a specific language or locale without opt-in is a natural-language policy concern unless the regional constraint is explicitly documented and justified, which is not present here.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
Line L17 states that x-axis labels must be in Chinese, which is a natural-language locale constraint. Because the file does not provide user opt-in or explain that this template is intentionally limited to a Chinese-language context, it violates the language/locale policy criteria.

Static analysis

No suspicious patterns detected.