Back to skill

Security audit

SZZG007 Product Promotion

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent marketing-email purpose, but it embeds SMTP credentials, disables mail security checks, and can write or send content with weak safeguards.

Review carefully before installing. Do not use the bundled email sender until the exposed SMTP credential is removed and rotated, TLS verification is restored, send actions require explicit approval, path inputs are validated, and generated HTML values are escaped. Expect generated files and downloaded images to be retained on disk under the configured asset directory.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/send-email.py:18
Finding
Hardcoded SMTP Credentials Exposed in Source Code<![CDATA[ ## Vulnerability Details **File Location**: `scripts/send-email.py:18-22` **Vulnerability Type**: Hardcoded authentication credentials **Risk Level**: Critical ### Vulnerable Code ```python # 配置 SMTP_HOST = "smtp.163.com" SMTP_PORT = 465 SMTP_USER = "m13430467261@163.com" SMTP_PASS = "FC27pgp77tc5Vvhv" SMTP_FROM = "Judy <m13430467261@163.com>" ``` The exposed values are subsequently used to authenticate: ```python with smtplib.SMTP_SSL(SMTP_HOST, SMTP_PORT, context=context) as server: server.login(SMTP_USER, SMTP_PASS) server.sendmail(SMTP_FROM, to_email, msg.as_string()) ``` ### Technical Analysis The sender contains a plaintext, live-looking SMTP username and password. Any person who can access the package or its source can recover these values without executing the Skill. This contradicts the documentation, which directs users to supply SMTP credentials through an environment configuration file. Embedding credentials in distributed source code prevents safe per-deployment secret management and causes the same account to be shared across all copies of the package. Removing the credential from the current file alone is insufficient if it has already been committed or published, because it may remain available through package archives or repository history. ### Attack Path 1. An attacker downloads or otherwise obtains the Skill package. 2. The attacker opens `scripts/send-email.py` and extracts `SMTP_USER` and `SMTP_PASS`. 3. The attacker attempts authentication against `smtp.163.com` on port 465. 4. If the credential remains valid, the attacker uses the mailbox to send unsolicited, fraudulent, or phishing messages. 5. Messages may appear to originate from the embedded account, damaging its reputation and potentially causing service suspension or blocklisting. ### Impact Assessment Successful exploitation may provide authenticated access to the configured SMTP account. The attacker could send messages as the exposed identity, consu ...[truncated 343 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Revoke and rotate the exposed SMTP password immediately. 2. Remove the credential from the source file and repository history. 3. Load secrets from environment variables or an approved secret manager: ```python import os SMTP_HOST = os.environ["SMTP_HOST"] SMTP_PORT = int(os.environ.get("SMTP_PORT", "465")) SMTP_USER = os.environ["SMTP_USER"] SMTP_PASS = os.environ["SMTP_PASS"] SMTP_FROM = os.environ["SMTP_FROM"] ``` 4. Fail closed with a clear configuration error if any required value is absent. 5. Ensure secret files are excluded from version control and stored with restrictive filesystem permissions. 6. Use separate, least-privileged SMTP credentials for each deployment. 7. Add automated secret scanning to pre-commit and CI workflows. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/send-email.py:68
Finding
SMTP Server Certificate Verification Is Explicitly Disabled<![CDATA[ ## Vulnerability Details **File Location**: `scripts/send-email.py:68-76` **Vulnerability Type**: Improper TLS certificate validation **Risk Level**: High ### Vulnerable Code ```python # 创建 SSL 上下文 (禁用证书验证用于测试) context = ssl.create_default_context() context.check_hostname = False context.verify_mode = ssl.CERT_NONE # 连接 SMTP 服务器 (SSL) with smtplib.SMTP_SSL(SMTP_HOST, SMTP_PORT, context=context) as server: server.login(SMTP_USER, SMTP_PASS) server.sendmail(SMTP_FROM, to_email, msg.as_string()) ``` ### Technical Analysis The script creates a secure default SSL context and then explicitly disables both certificate-chain validation and hostname verification. Consequently, the client encrypts the connection but does not establish that the remote endpoint is the legitimate SMTP server. Any TLS certificate, including a self-signed certificate controlled by an attacker, will be accepted. This makes the SMTP session susceptible to machine-in-the-middle interception when an attacker can influence DNS, routing, a local proxy, the gateway, or another relevant network layer. The comment indicates this was done for testing, but the behavior is present in the production sender and protects authentication credentials and recipient message content. ### Attack Path 1. The victim invokes `scripts/send-email.py`. 2. A network-positioned attacker redirects or intercepts the connection intended for `smtp.163.com`. 3. The attacker presents an arbitrary TLS certificate. 4. The script accepts the certificate because hostname and certificate verification are disabled. 5. The client authenticates to the attacker-controlled endpoint using the SMTP username and password. 6. The attacker captures authentication material and can inspect, suppress, or modify the outgoing email. ### Impact Assessment An attacker with a suitable network position may obtain the SMTP credential, recipient address, subject, and full email body. The attacker may also tamper with messag ...[truncated 246 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not modify the secure defaults returned by `ssl.create_default_context()`. 2. Remove these assignments: ```python context.check_hostname = False context.verify_mode = ssl.CERT_NONE ``` 3. Use certificate and hostname verification: ```python context = ssl.create_default_context() with smtplib.SMTP_SSL( SMTP_HOST, SMTP_PORT, context=context, ) as server: server.login(SMTP_USER, SMTP_PASS) server.send_message(msg) ``` 4. If a private certificate authority is required, configure an explicit trusted CA bundle rather than disabling verification. 5. Abort transmission on all TLS validation errors. 6. Add an integration test that verifies untrusted certificates and hostname mismatches are rejected. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/product-promotion.py:203
Finding
Unvalidated Code Values Permit Path Traversal and Filesystem Escape<![CDATA[ ## Vulnerability Details **File Location**: `scripts/product-promotion.py:203-210` **Additional Locations**: `scripts/product-promotion.py:223-230`, `scripts/product-promotion.py:296-345`, `scripts/email-code-manager.py:141-149` **Vulnerability Type**: Path traversal leading to arbitrary file creation, overwrite, or read **Risk Level**: High ### Vulnerable Code The custom code is inserted directly into output filenames: ```python def save_email(html: str, product_id: str, custom_code: str = None) -> str: """保存邮件模版""" print(f"\n💾 正在保存邮件模版...") # 如果有自定义代号,使用代号作为文件名 if custom_code: filename = f"{custom_code}-{product_id}.html" else: filename = f"{product_id}.html" filepath = EMAILS_DIR / filename with open(filepath, 'w', encoding='utf-8') as f: f.write(html) ``` The same pattern is used for reports: ```python if custom_code: filename = f"{custom_code}-{report_id}.md" else: filename = f"{report_id}.md" filepath = REPORTS_DIR / filename ``` Metadata creation also uses the unvalidated code: ```python filepath = EMAILS_DIR / f"{code}.meta.json" with open(filepath, 'w', encoding='utf-8') as f: json.dump(meta, f, indent=2, ensure_ascii=False) ``` The management script constructs a read path from a command-line value: ```python def get_code_info(code: str): """查看代号详情""" meta_file = EMAILS_DIR / f"{code}.meta.json" if not meta_file.exists(): print(f"❌ 未找到代号:{code}") return with open(meta_file, 'r', encoding='utf-8') as f: meta = json.load(f) ``` ### Technical Analysis The documented code format is limited to values such as `QB1` or `QY2`, but neither script enforces this syntax. User-controlled `--code` and `info <code>` values are joined to trusted base directories without rejecting absolute paths, path separators, or `..` traversal components. `pathlib` path joining does not by itself guarantee that the resulting path re ...[truncated 1696 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce the documented code grammar before using a value in any path: ```python import re CODE_PATTERN = re.compile(r"Q[YBAHF][1-9][0-9]*\Z") def validate_code(code: str) -> str: if not CODE_PATTERN.fullmatch(code): raise ValueError("Invalid promotion code") return code ``` 2. Reject all path separators, absolute paths, control characters, and traversal components. 3. Resolve every destination and verify that it remains beneath the intended base directory: ```python def safe_child(base: Path, filename: str) -> Path: base = base.resolve() candidate = (base / filename).resolve() if not candidate.is_relative_to(base): raise ValueError("Path escapes the asset directory") return candidate ``` 4. Apply the same validation to `save_email`, `generate_report`, `save_email_meta`, and `get_code_info`. 5. Use exclusive creation mode (`"x"`) where replacing an existing asset is not intended. 6. Where replacement is required, explicitly confirm overwrite behavior and reject symlinks. 7. Add tests for `../`, absolute paths, nested separators, Unicode separator variants, and symlink-based escape attempts. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/product-promotion.py:117
Finding
Unescaped Product Data Is Inserted into HTML Email Attributes and Content<![CDATA[ ## Vulnerability Details **File Location**: `scripts/product-promotion.py:117-138` **Additional Locations**: `scripts/product-promotion.py:145-164`, `templates/email-template-v1.html:34`, `templates/email-template-v1.html:92`, `templates/email-template-v1.html:142`, `templates/email-template-v1.html:165` **Vulnerability Type**: HTML and attribute injection in generated email content **Risk Level**: Medium ### Vulnerable Code Product values are inserted through unrestricted string replacement: ```python replacements = { '{{BRAND_NAME}}': product_info.get('brand', 'MOSSRIVER'), '{{BRAND_TAGLINE}}': product_info.get('tagline', 'Elevate Your Space'), '{{PRODUCT_TITLE}}': product_info.get('title', 'Premium Product'), '{{ORIGINAL_PRICE}}': product_info.get('original_price', '$0.00'), '{{SALE_PRICE}}': product_info.get('sale_price', '$0.00'), '{{SAVE_AMOUNT}}': product_info.get('save_amount', '$0.00'), '{{DISCOUNT_PERCENT}}': product_info.get('discount_percent', '0'), '{{PRODUCT_URL}}': product_info.get('url', '#'), '{{MAIN_IMAGE}}': image_data['images'][0]['url'] if image_data['images'] else '', } for key, value in replacements.items(): html = html.replace(key, str(value)) # 生成图片画廊 HTML gallery_html = generate_image_gallery(image_data) html = html.replace('{{IMAGE_GALLERY}}', gallery_html) # 生成特点列表 HTML features_html = generate_features_html(product_info.get('features', [])) html = html.replace('{{FEATURES}}', features_html) ``` Gallery URLs are also interpolated directly: ```python img = images[i + j] html += f' <td style="padding: 8px;">\n' html += f' <img src="{img["url"]}" alt="Product Image {i+j+1}" ' html += f'style="width: 100%; border-radius: 8px; display: block;">\n' html += f' </td>\n' ``` The template places the unescaped product URL into multiple HTML attributes: ```html <a href="{{PRODUCT_URL}}" style="display: inline-block; padding: 16px 48px; color: #ffffff; text-decoration: none ...[truncated 2398 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use a maintained template engine with automatic HTML escaping enabled. 2. Apply context-appropriate escaping to every text and attribute value: ```python from html import escape safe_title = escape(str(product_info["title"]), quote=True) safe_brand = escape(str(product_info["brand"]), quote=True) ``` 3. Parse and validate all link and image URLs before rendering: ```python from urllib.parse import urlparse def validate_web_url(value: str) -> str: parsed = urlparse(value) if parsed.scheme not in {"http", "https"} or not parsed.netloc: raise ValueError("Only absolute HTTP(S) URLs are permitted") return value ``` 4. Escape validated URL values with `quote=True` before placing them in HTML attributes. 5. Reject control characters and malformed URLs. 6. Construct gallery and feature markup through escaped templates rather than f-string concatenation. 7. Add security tests using quotation marks, angle brackets, entity encodings, unsafe schemes, and malformed URLs. 8. Preview and approve generated email content before transmission, especially when source metadata is obtained from an external website. ]]>
Vulnerability Patterns
  • 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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (22)

Hidden Instructions

High
Category
Prompt Injection
Content
</head>
<body style="margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; background-color: #f8f9fa;">
  
  <!-- Preheader -->
  <div style="display: none; max-height: 0; overflow: hidden;">
    ✨ {{PRODUCT_TITLE}} - Special Offer Inside!
  </div>
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The README explicitly instructs users to send generated emails and configure SMTP credentials, but it does not warn that content and recipient data will be transmitted to external mail infrastructure. In a skill that automates scraping product data and generating outbound marketing email, this omission can cause users to disclose sensitive content, credentials, or recipient information without informed consent.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill explicitly advertises direct email sending as a core capability but does not require an explicit confirmation, recipient review, or warning that generated content and recipient data will be transmitted to an external SMTP service. In an agent setting, this increases the risk of unintended data exfiltration, accidental sending to the wrong recipient, or unauthorized outbound communications triggered from a user prompt.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The example workflow shows content generation and email sending as a seamless single request, with the assistant reporting success rather than requiring a separate approval step. This normalizes autonomous outbound messaging behavior and can lead operators or downstream agents to send generated content externally without adequate verification of recipient, content safety, or authorization.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
The description forces Chinese-language interaction in the skill metadata, which can violate language/locale policy when no user opt-in or alternative language is provided. Nothing in the manifest indicates this skill is intentionally limited to a Chinese-speaking region or offers a language choice.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This markdown file contains all user-facing instructions in Chinese, including headings, operational guidance, and warnings, but does not indicate that language selection is optional or that the skill is intentionally limited to Chinese-speaking users. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
This markdown file presents all user inputs, responses, best practices, and FAQ content exclusively in Chinese. Under the policy rule, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is clearly justified, which is not stated here.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This code file contains natural-language instructions and CLI help text that assume Chinese for all users. Under the policy, forcing a specific language without offering a user choice or documenting a justified locale constraint is a policy violation.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
Beyond the module docstring, the command output, errors, and usage guidance are all presented only in Chinese. This continues the same language-policy issue by requiring a single locale for interaction without giving users an alternative or recording a justified regional limitation.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The module documentation says the skill extracts images from a product webpage to generate a promotion email. In the implementation, `main()` constructs `image_urls` as fixed `https://example.com/image1.jpg` and `image2.jpg` values rather than extracting anything from `product_url`, so the documented behavior is contradicted by the actual code path.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The script performs external network access to download remote images without a clear prior warning or consent step. In agent/skill contexts this is security-relevant because it can leak environment metadata through outbound requests, contact untrusted infrastructure, and fetch hostile content unexpectedly.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
# 使用 curl 下载
            cmd = ['curl', '-L', '-sS', '-o', str(filepath), url]
            result = subprocess.run(cmd, capture_output=True, timeout=30)
            
            if result.returncode == 0 and filepath.exists():
                size = filepath.stat().st_size
Confidence
94% confidence
Finding
The script makes outbound network requests by invoking curl on attacker-controlled or untrusted URLs derived from workflow input. Although shell injection is avoided by passing a list to subprocess.run, this still creates SSRF-style risk, unexpected external connectivity, and downloads untrusted content to disk without validation of scheme, host, content type, or size.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
This code file performs persistent file writes to user-local workspace directories for HTML emails, reports, and metadata. While it prints success messages after saving, there is no upfront disclosure, confirmation, or caution that running the script will create and archive files in these locations.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The inline comment indicates this block is standing in for data that should be extracted from the webpage, but the rest of the program proceeds as if it generated a real promotion artifact for the given product URL. The actual behavior uses synthetic title, pricing, and features unrelated to the target page, which diverges from the skill's stated intent of generating promotion content from the product URL.

Intent-Code Divergence

Medium
Confidence
99% confidence
Finding
The comment explicitly says the image URLs should come from webpage extraction, yet the implementation supplies constant placeholder URLs from `example.com`. This is a direct contradiction between the inline documentation and what the code actually downloads.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
This code file contains natural-language strings and docstrings in Chinese only, including the top-level usage instructions. The policy requires avoiding forced language or locale constraints unless the skill offers user choice or clearly documents that it is region- or locale-specific.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The script's runtime output, including errors and progress messages, is emitted only in Chinese. For a general-purpose skill, this constitutes a language-policy issue because users are not given an opt-in or alternative locale.

Intent-Code Divergence

Medium
Confidence
99% confidence
Finding
The script explicitly disables TLS certificate and hostname verification before authenticating to the SMTP server. That allows a man-in-the-middle attacker on the network path to impersonate the mail server, intercept the SMTP credentials embedded in the script, and read or alter email contents in transit. The hardcoded username/password make this more dangerous because a successful interception immediately yields reusable account credentials.

Missing User Warnings

Low
Confidence
82% confidence
Finding
The README states that product images, HTML emails, and reports are automatically written to persistent local directories, but it does not disclose that user-supplied URLs and generated content will be retained on disk. This can expose sensitive marketing material, scraped data, or user-provided targets to other local users, backups, or later unintended reuse.

Unverifiable Dependency: openclaw has 16 known advisory(ies) (CVE-2026-53846 (OpenClaw: Workspace .env npm_execpath could influence bundled runtime dependency); CVE-2026-32064 (OpenClaw's andbox browser noVNC observer lacked VNC authentication); CVE-2026-32006 (OpenClaw has a BlueBubbles group allowlist mismatch via DM pairing-store fallbac) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
72% confidence
Finding
The manifest declares a peer dependency on openclaw using a broad version range (>=2026.2.0) while the analyzer indicates multiple known advisories affecting that package family. Because the version is not pinned or constrained to a verified fixed release, installations may resolve to a vulnerable version, which is risky in a skill that automates web content retrieval, template generation, archiving, and optional email sending.

Intent-Code Divergence

Low
Confidence
92% confidence
Finding
The top-level documentation says the code rules cover Y, B, and A categories, but the actual CODE_TYPES mapping also supports H (Home) and F (Fashion). This is an active contradiction between the documented category scheme and implemented behavior, not merely an omitted implementation detail, because users are told what valid code classes exist.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
The HTML root sets `lang="en"`, which indicates a fixed English-language template. Under the policy rule, forcing a specific language without opt-in or justification is a natural-language locale constraint that should be documented or made configurable.

Static analysis

No suspicious patterns detected.