Back to skill

Security audit

Pdd Promotion Analysis

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent paid PDD analysis purpose, but it uploads business reports to a remote service, stores credentials and reports locally, and renders remote HTML in a way that needs review before installation.

Install only if you are comfortable sending PDD promotion spreadsheets and optional operation logs to aituiguangbao.com for paid analysis. Use it with explicit user confirmation before staging files, keep the Alipay payment flow user-directed, avoid passing Payment-Proof manually, and treat generated HTML reports as remote content; prefer opening reports in a constrained viewer and delete ~/.pdd_skill credentials/reports when no longer needed.

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/pdd_analyzer.py:889
Finding
Unsanitized Remote HTML Is Written to Locally Opened Reports<![CDATA[ ## Vulnerability Details **File Location**: `scripts/pdd_analyzer.py:889-923`, with the resulting document written at `scripts/pdd_analyzer.py:1097-1106` **Vulnerability Type**: Improper neutralization of remotely supplied active HTML **Risk Level**: High ### Vulnerable Code ```python if not report_html: return "" chart_data = (sections or {}).get("chart_data") or {} html = report_html ``` ```python warnings_html = _render_api_warnings(api_warnings) return _wrap_html_document(warnings_html + html) ``` ```python def _save_html_report(html: str) -> str: """将完整 HTML 报告写到本地文件,返回路径(供 stdout 指引) token 优化:stdout 不回传 HTML+SVG(SVG 对 LLM 无意义,~7-13K token 纯浪费), 改回传 report markdown(~2K token);HTML 写文件供浏览器/IDE 渲染查看。 """ CONFIG_DIR.mkdir(parents=True, exist_ok=True) ts = pd.Timestamp.now().strftime("%Y%m%d_%H%M%S") path = CONFIG_DIR / f"report_{ts}.html" path.write_text(html, encoding="utf-8") return str(path) ``` ### Technical Analysis The `report_html` value originates from the remote paid API response. The renderer assigns this value directly to `html`, combines it with warning markup, and places it into a complete HTML document without applying an HTML allowlist sanitizer. The generated report is saved under `~/.pdd_skill/`, and the user is explicitly instructed to open it in a browser or IDE. If the analysis service, its infrastructure, or the response-generation pipeline is compromised, the response can contain active content such as: - `<script>` elements. - Inline event handlers such as `onerror` or `onclick`. - External images or other resources that create tracking requests. - Iframes, forms, redirects, or deceptive payment interfaces. - Unsafe URL schemes or browser-specific active content. The same output boundary also affects API warning messages, which are interpolated into HTML without escaping in `_render_api_warnings`. No Content Security Policy is added to the generated document. Consequently, th ...[truncated 1971 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not accept server-generated HTML as trusted presentation content. Prefer returning structured JSON fields and constructing all markup locally. 2. If HTML support is required, sanitize it with a maintained allowlist sanitizer before document composition. 3. Allow only the minimum necessary elements, such as static headings, paragraphs, lists, and tables. 4. Remove at least: - `script`, `iframe`, `object`, `embed`, `form`, `input`, `button`, `meta`, `base`, and `link` elements. - All inline event-handler attributes. - `srcdoc`, unsafe `style` content, and dangerous URL schemes. - External resource URLs unless they are strictly required and validated. 5. HTML-escape API and local warning messages before interpolation. 6. Add a restrictive Content Security Policy to generated reports, such as: ```html <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src data:; font-src 'none'; connect-src 'none'; frame-src 'none'; form-action 'none'; base-uri 'none'"> ``` 7. Add automated security tests containing scripts, event handlers, iframes, external images, unsafe links, and malformed markup. Verify that generated reports contain no active content. 8. Consider rendering reports as Markdown or plain text by default and making HTML generation an explicit option. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/pdd_analyzer.py:54
Finding
API Credentials and Sensitive Reports Are Stored Without Explicit Restrictive Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/pdd_analyzer.py:54-57` and `scripts/pdd_analyzer.py:1097-1124` **Vulnerability Type**: Insecure local storage permissions and indefinite sensitive-data retention **Risk Level**: Medium ### Vulnerable Code ```python def save_config(config: dict): CONFIG_DIR.mkdir(parents=True, exist_ok=True) with open(CONFIG_FILE, "w", encoding="utf-8") as f: json.dump(config, f, indent=2) ``` ```python def _save_html_report(html: str) -> str: """将完整 HTML 报告写到本地文件,返回路径(供 stdout 指引) token 优化:stdout 不回传 HTML+SVG(SVG 对 LLM 无意义,~7-13K token 纯浪费), 改回传 report markdown(~2K token);HTML 写文件供浏览器/IDE 渲染查看。 """ CONFIG_DIR.mkdir(parents=True, exist_ok=True) ts = pd.Timestamp.now().strftime("%Y%m%d_%H%M%S") path = CONFIG_DIR / f"report_{ts}.html" path.write_text(html, encoding="utf-8") return str(path) def _save_markdown_report(md: str) -> str: """将纯文本/Markdown 报告写到本地文件,返回路径。""" CONFIG_DIR.mkdir(parents=True, exist_ok=True) ts = pd.Timestamp.now().strftime("%Y%m%d_%H%M%S") path = CONFIG_DIR / f"report_{ts}.md" path.write_text(md, encoding="utf-8") return str(path) def _save_json_report(payload: dict) -> str: """将 API 原始 JSON 响应写到本地文件,返回路径(适合二次开发/调试)。""" CONFIG_DIR.mkdir(parents=True, exist_ok=True) ts = pd.Timestamp.now().strftime("%Y%m%d_%H%M%S") path = CONFIG_DIR / f"report_{ts}.json" path.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8") return str(path) ``` ### Technical Analysis The Skill stores the remotely issued API key in `~/.pdd_skill/config.json`. It also stores HTML, Markdown, and JSON reports in the same directory. These reports can contain product identifiers, advertising performance information, operation history, diagnostic conclusions, and other commercially sensitive data. Neither the directory nor the files are created with explicit restrictive permission modes. Their effec ...[truncated 1945 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create the storage directory with owner-only permissions: ```python CONFIG_DIR.mkdir(parents=True, exist_ok=True, mode=0o700) os.chmod(CONFIG_DIR, 0o700) ``` 2. Create credential and report files atomically with mode `0600`, rather than relying on `open()` or `Path.write_text()` defaults. 3. Write credentials through a temporary file in the same protected directory, apply mode `0600`, flush and synchronize it, and atomically replace the destination. 4. Validate and repair permissions on existing directories and files during startup. 5. Store the API key in the operating system's credential manager when available. 6. Add a report-cleanup command and configurable retention period. 7. Avoid storing the complete raw API response unless the user explicitly selects JSON output. 8. Clearly disclose that reports persist after rendering and provide instructions for secure deletion. 9. Ensure `reset` can optionally remove both credentials and generated reports after explicit user confirmation. 10. Add tests that run under permissive umask settings and verify that all sensitive files remain owner-readable and owner-writable only. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (25)

Vague Triggers

Medium
Confidence
95% confidence
Finding
The trigger phrases include very generic language such as '看看情况', '分析下这个商品怎么样', and '该不该调价', which can overlap with ordinary conversation and cause the skill to activate in contexts the user may not have intended. In this skill, unintended activation is more dangerous because the workflow encourages file upload and remote API use, increasing the chance of accidental data transfer or paid actions.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The README says credentials are automatically applied for and stored locally '无感知', which means users may not realize a credentialing flow is occurring or that a persistent token is being written to disk. Silent credential creation/storage weakens informed consent and can expose users to misuse of the credential, confusion about account linkage, or persistence of sensitive access material on shared systems.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The documentation states that files are first staged to a remote `/api/stage` endpoint, but this network transfer is described as an implementation detail rather than a privacy-relevant action requiring prominent warning. Because users are expected to upload business promotion data, undisclosed remote staging can result in inadvertent disclosure of sensitive commercial information and is made riskier here by the skill's broad triggers and automated workflow.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill describes capabilities that read local files, write files, and make network requests, but it does not declare any explicit tool scope or allowed-tools boundary. In an agent environment, missing permission constraints can allow the skill to be invoked with broader tool access than intended, increasing the risk of unauthorized file access, persistence, or external data exfiltration.

Vague Triggers

Medium
Confidence
96% confidence
Finding
The skill advertises broad trigger phrases like generic requests to 'analyze' or 'take a look,' which can overlap with ordinary conversation and unrelated spreadsheet workflows. This raises the chance of unintended invocation, causing accidental file handling, payment-flow initiation, or data transmission to a remote service without the user clearly intending to use this paid skill.

Vague Triggers

Medium
Confidence
97% confidence
Finding
The trigger section repeats ambiguous everyday phrases without strong scope checks, which increases the risk that the agent routes unrelated requests into this skill. Because this skill stages files remotely and initiates a paid API workflow, accidental invocation has privacy and billing implications beyond a harmless misroute.

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

Medium
Category
Data Flow
Content
api_key = config.get("api_key")
    if api_key:
        try:
            resp = requests.get(f"{API_BASE}/api/status", headers={"api-key": api_key}, timeout=10)
            if resp.status_code == 200:
                return api_key
        except Exception:
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.

External Transmission

Medium
Category
Data Exfiltration
Content
pass

    try:
        resp = requests.post(f"{API_BASE}/api/register", json={}, timeout=15)
        resp.raise_for_status()
        data = resp.json()
        if data.get("code") == "SUCCESS":
Confidence
90% confidence
Finding
This code transmits data to an external service for automatic registration. External transmission is expected in this skill's design, but it remains security-relevant because it creates outbound connectivity and service dependency without an explicit local trust decision at runtime.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill uploads local report files and optional operation logs to a remote domain as part of its workflow, but the runtime path shown here does not present a clear consent prompt or prominent disclosure at the moment of transmission. Because these files may contain business-sensitive promotion data, product identifiers, and operational history, silent upload materially increases confidentiality and privacy risk.

Tainted flow: 'data' from requests.post (line 74, network input) → requests.post (network output)

Medium
Category
Data Flow
Content
if ops_file:
                ops_handle = open(ops_file, "rb")
                files["ops_file"] = (Path(ops_file).name, ops_handle)
            resp = requests.post(
                f"{API_BASE}/api/stage",
                files=files, data=data, headers=headers, timeout=120,
            )
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.

External Transmission

Medium
Category
Data Exfiltration
Content
if payment_proof:
        headers["Payment-Proof"] = payment_proof
    try:
        resp = requests.post(
            f"{API_BASE}/api/analyze",
            json={"staging_id": staging_id},
            headers=headers, timeout=180,
Confidence
94% confidence
Finding
The script sends staged analysis identifiers and optionally payment-related authorization context to an external API to obtain the report. In this skill context, outbound transmission is the core business function, but it is still sensitive because the tool handles commercial data analysis and payment-gated access, so users should be clearly informed and the transmission surface tightly controlled.

Description-Behavior Mismatch

Medium
Confidence
86% confidence
Finding
The shell exposes a `payment_proof` parameter and forwards it as a `Payment-Proof` header, allowing local callers to directly invoke the paid analysis endpoint if they can supply or replay a proof. This weakens the stated boundary that analysis results must only flow through the payment-controlled path and increases the chance of credential/proof misuse, replay, or unauthorized automation around a paid resource.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The README presents the skill name, usage instructions, and invocation phrases entirely in Chinese and only gives Chinese examples for interacting with the agent. There is no statement that the skill is intentionally China-region or Chinese-only, nor any opt-in or alternative language path for users who operate in other languages.

Natural-Language Policy Violations

Low
Confidence
71% confidence
Finding
The activation description and examples are written as fixed Chinese trigger phrases and do not indicate that users may interact in another language or choose their preferred locale. This can constitute a language-policy issue when a skill implicitly constrains interaction language without opt-in or explicit justification.

Unpinned Dependencies

Low
Category
Supply Chain
Content
pandas>=2.0.0
openpyxl>=3.1.0
xlrd>=2.0.0
requests>=2.28.0
Confidence
95% confidence
Finding
The dependency is specified with a minimum version only, which allows future installs to resolve to different versions over time. This weakens build reproducibility and can unintentionally introduce vulnerable or incompatible releases from the supply chain.

Unverifiable Dependency: pandas has 1 known advisory(ies) (CVE-2020-13091 (** DISPUTED ** pandas through 1.0.3 can unserialize and execute commands from an)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Unpinned Dependencies

Low
Category
Supply Chain
Content
pandas>=2.0.0
openpyxl>=3.1.0
xlrd>=2.0.0
requests>=2.28.0
Confidence
95% confidence
Finding
Using an unpinned version for openpyxl means the installed package may vary by environment or over time. That increases supply-chain risk and makes it harder to ensure the deployed version is free of known parser-related issues.

Unverifiable Dependency: openpyxl has 2 known advisory(ies) (CVE-2017-5992 (Improper Restriction of XML External Entity Reference in Openpyxl); CVE-2017-5992 (Openpyxl 2.4.1 resolves external entities by default, which allows remote attack)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Unpinned Dependencies

Low
Category
Supply Chain
Content
pandas>=2.0.0
openpyxl>=3.1.0
xlrd>=2.0.0
requests>=2.28.0
Confidence
92% confidence
Finding
The xlrd requirement is not pinned to a single version, so dependency resolution may pull different releases in different environments. This creates reproducibility and supply-chain integrity issues even if no specific exploit is demonstrated in this file.

Unpinned Dependencies

Low
Category
Supply Chain
Content
pandas>=2.0.0
openpyxl>=3.1.0
xlrd>=2.0.0
requests>=2.28.0
Confidence
97% confidence
Finding
An unpinned requests dependency is riskier because it is commonly used for outbound network access and has a history of security advisories. Allowing any version above a minimum can result in deployment of a release with unresolved credential leakage, verification, or transport-security issues.

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +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
40% confidence
Finding
Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Missing User Warnings

Low
Confidence
86% confidence
Finding
The script automatically registers with a remote service and persists the returned API key locally without an explicit runtime disclosure or consent checkpoint. This is lower impact than file upload, but it still creates an undisclosed network side effect and leaves a credential on disk that another local process or user might recover if permissions are weak.

Natural-Language Policy Violations

Low
Confidence
90% confidence
Finding
The HTML wrapper sets `lang="zh-CN"`, which fixes the output locale to Simplified Chinese. There is no indication in this file that the user can choose another language or that the locale restriction is documented as an intentional region-specific constraint.

Intent-Code Divergence

Low
Confidence
94% confidence
Finding
The CLI argument parser documentation states `--product-id` is available for explicit override. But in `analyze()`, `effective_product_id` is initialized to `None` and only populated from the ops log; the provided `product_id` argument is never used as a fallback or override before uploading in `stage_files()`. This is an active documentation/code contradiction, not merely an omission.

Intent-Code Divergence

Low
Confidence
95% confidence
Finding
The command-line help explicitly tells users that `--product-id` is supported as an explicit override. In practice, the value parsed into `args.get("product_id")` is passed into `analyze()`, but `analyze()` discards it and only uses product IDs extracted from the ops log. The help text therefore contradicts actual behavior.

Static analysis

No suspicious patterns detected.