Back to skill

Security audit

AIDSO-GEO-diagnostic-report

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed AIDSO GEO report workflow with scoped paid API calls, local work files, and no evidence of hidden persistence or exfiltration.

Install only if you trust the AIDSO workflow and are comfortable providing an AIDSO API key for the current session, explicitly confirming paid task submissions, and keeping task metadata/raw responses in the workspace. Be aware that generated HTML reports can load remote product images when opened, so review or strip image URLs before sharing reports in sensitive environments.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/render_report.py:311
Finding
Untrusted Product Image URLs Trigger Automatic Third-Party Network Requests<![CDATA[ ## Vulnerability Details **File Locations**: - `scripts/normalize_results.py:96-106` - `scripts/render_report.py:119-128` - `scripts/render_report.py:311-316` - `scripts/render_report.py:94` **Vulnerability Type**: Unrestricted embedding of untrusted remote resources **Risk Level**: Medium ### Vulnerable Code The normalization layer accepts image URLs directly from untrusted API card data: ```python def normalize_card(kind: str, item: dict, position: int) -> dict: title = first_nonempty(item, ["text", "title", "sku_name", "name", "poi_name", "query"]) card_id = first_nonempty(item, ["pid", "item_id", "sku", "id", "poi_id", "wx_app_id", "source_seq_id"]) url = first_nonempty(item, ["jump_url", "auctionURL", "pc_url", "webURL", "poi_url"]) image = first_nonempty(item, ["image_url", "pic_path", "verticalPic", "photos", "icon"]) shop = first_nonempty(item, ["seller_name", "shop_name", "venueName", "source"]) price = first_nonempty(item, ["price", "priceShowText", "priceLow", "minPrice", "priceStr"]) return { "kind": kind, "position": position, "id": str(card_id) if card_id is not None else None, "title": str(title) if title is not None else None, "shop": str(shop) if shop is not None else None, "price": price, "image_url": str(image) if image is not None else None, "url": str(url) if url is not None else None, "raw": item, } ``` The renderer considers every HTTP or HTTPS host safe: ```python def safe_url(value: Any) -> Optional[str]: if not isinstance(value, str): return None value = value.strip() try: parsed = urlsplit(value) except ValueError: return None return value if parsed.scheme in {"http", "https"} and parsed.netloc else None ``` It then embeds the untrusted URL as an automatically loaded image: ```python def render_product_cards(block: dict) -> str: output = [] for item in block.get("i ...[truncated 3443 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Do not embed untrusted remote images by default.** - Replace remote product images with local placeholders. - Where source access is useful, provide an ordinary user-activated link rather than an automatically loaded resource. 2. **Tighten the report CSP.** - Prefer: ```text img-src 'self' data: ``` - If approved remote providers are indispensable, enumerate their exact HTTPS origins rather than allowing all HTTPS hosts. 3. **Use a controlled image-fetching pipeline if images must be included.** - Maintain an explicit hostname allowlist. - Resolve DNS and reject loopback, private, link-local, multicast, reserved, and metadata-service address ranges. - Repeat destination validation after every redirect. - Limit redirect count, response size, download time, and image dimensions. - Require an approved image media type and verify the file signature rather than trusting `Content-Type`. - Strip metadata where appropriate. - Embed the validated result locally or as a size-limited data URL. 4. **Strengthen URL validation.** - Reject username/password components. - Permit only HTTPS unless a documented requirement justifies HTTP. - Normalize hostnames and ports before allowlist comparison. - Reject malformed or ambiguous host representations. 5. **Extend report validation.** - Fail validation if an image source is not a local/data resource or an explicitly approved origin. - Add tests for attacker-controlled hosts, loopback addresses, private addresses, URL credentials, redirects, IPv6 literals, and DNS-rebinding scenarios. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (23)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared description is substantially broader than the code's actual behavior. The code supports only two concrete actions: submit a GEO task with a prompt/platform/thinking flag, and query a result by reqId. This does align with the 'query task IDs without polling' and partial 'submit' aspects, but the description also promises several higher-level features that are absent: chat-based key binding, pricing, brand-diagnosis-specific handling, raw conversation retrieval semantics, and HTML report generation with product-layer analysis. Therefore the description does not accurately represent the supplied code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared purpose is centered on GEO diagnosis workflow features and AIDSO API operations: binding keys, submitting paid jobs, querying task IDs, retrieving conversations, and generating reports. The supplied code does none of those things. Instead, it defines regex patterns for internal platform codes and field names, parses HTML to extract visible text, and scans text for likely user-facing leaks of internal schema/API artifacts. This is a materially different primary purpose and an undeclared capability unrelated to the declared GEO diagnosis and API-binding behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description presents an integration/reporting skill centered on API key management, paid task submission, task lookup, conversation retrieval, and HTML report generation. The supplied code does none of those things. Instead, it only reads a local JSON file, validates numeric/count fields, computes a weighted brand score from five metrics, and prints JSON results. There is no network access, no API interaction, no task management, no conversation retrieval, and no HTML generation. This is a materially different primary purpose, so the description does not accurately represent the code.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description presents a broad end-user skill for interacting with the AIDSO service: binding credentials, submitting/quoting paid diagnosis tasks, checking task IDs, retrieving raw conversations, and generating a Chinese HTML diagnostic report. The actual code does none of the credential management, submission, pricing, task-querying, or HTML report generation. Instead, it only processes existing JSON response files inside specific workspace directories, extracts/normalizes conversation content and embedded card payloads, and writes normalized JSON. While this could support the narrower declared item 'retrieve raw AI conversations,' its primary behavior is offline parsing/normalization of already-fetched results, which is only a small subset of the declared purpose. Therefore the description does not accurately represent what this code chunk actually does.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description presents an operational AIDSO integration skill that can bind credentials, submit paid diagnoses, query tasks, retrieve conversations, and generate reports. This code does none of those external-facing actions. Its primary purpose is only to locally validate and prepare a diagnosis plan/manifest, calculate estimated points, and format a confirmation message. The script explicitly states it never calls a network service, and there is no code for API authentication, remote submission, task lookup, polling alternatives, conversation retrieval, or HTML report generation. While the manifest includes fields related to report path and product information, those are only planning metadata, not implementation of the declared end-user capabilities.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The code chunk’s primary function is narrow: render and validate an audited GEO report model into safe HTML. It includes optional product-layer handling, Chinese report generation, provenance display, CSP hardening, leak detection, and filesystem path restrictions. This partially matches only the declared report-generation portion ('generate a Chinese HTML GEO diagnostic report with optional product-layer analysis'). However, most of the declared capabilities are absent: there is no network/API interaction, no credential binding flow, no pricing or payment logic, no task lookup mechanism, and no conversation retrieval. Because the description presents a broader multi-function skill while the code only implements report rendering/validation, the description does not accurately represent the supplied code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The description presents a broad end-user skill for interacting with AIDSO services, including key binding, paid diagnosis submission, retrieving conversations, and generating reports. The supplied code chunk does something much narrower and different: it is a local filesystem-based task registry utility. Its commands only read/write local JSON manifests, enforce confirmation text and plan-digest checks, reserve jobs, bind request IDs after external submission, mark ambiguous/recovered cases, update local status, summarize, and find manifests. The only partial overlap is 'query task IDs without polling,' since the find command can locate manifests by diagnosis ID, task name, or request_id locally. However, that overlap is small relative to the rest of the declared functionality, and the code's primary purpose is materially different from the declared skill description. Therefore this is a clear mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description presents an operational/report-generation skill centered on AIDSO API interactions and GEO diagnosis workflows. The code shown does none of that. Instead, it validates an already-rendered HTML report for structural correctness and security/safety invariants: allowed tags, CSP, inline CSS exact-match, section ordering, provenance panel content, score formatting, and leak detection. This is a materially different primary purpose, and it introduces an undeclared capability—local report validation/security auditing—while lacking the core declared capabilities such as API binding, job submission, task querying, conversation retrieval, or report generation.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
if name in directives:
            raise ValueError(f"重复 CSP 指令:{name}")
        directives[name] = parts[1:]
    return directives


def csp_errors(values: list[str]) -> list[str]:
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
92% confidence
Finding
The skill describes workflows that require file I/O, environment access, and network/API interaction, but it does not declare any explicit tool scope or allowed-tools boundary. This weakens least-privilege controls and can let the runtime grant broader capabilities than users or reviewers expect, increasing the blast radius if the skill is modified or misused.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The instructions require that all user-visible content use only Chinese business labels and full platform names. This is a language policy constraint applied unconditionally, with no indication that the user can choose another language or opt in to Chinese-only output.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
L041 规定 `confirmed_scope.platform_modes` “只接受”平台完整名称加“中文模式”,并明确不得使用英文模式值。这属于自然语言层面的语言/locale 强制要求,但文档中未见用户可选择其他语言,也未说明这是特定区域合规或业务必要性的例外。

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The document is written as a mandatory report specification in Chinese and explicitly requires Chinese-mode presentation details, including Chinese labels in user-visible text. This imposes a specific language/locale on outputs without offering user choice or documenting a region-specific justification, which matches the policy's language/locale violation criteria.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This code embeds user-facing natural-language strings entirely in Chinese, including the formula version and validation/error messages, which effectively imposes a specific language on users. The file does not indicate that the skill is region-specific or provide any opt-in or alternative locale handling.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
This Python file contains multiple natural-language strings shown to users in Chinese, including validation errors and argument labels, and there is no indication that the skill is explicitly region-specific or that users can opt into the locale. The policy requires avoiding forced language or locale without user choice or clear justification.

Intent-Code Divergence

Medium
Confidence
81% confidence
Finding
The docstring states this script 'never calls a network service' and only creates a local manifest. However, the script embeds operational metadata and user-facing confirmation text that reference a live remote API endpoint and future API submission flow, which contradicts the absolute wording of the documentation. This is an intent/documentation mismatch rather than a runtime network call in this file.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The script's user-facing messages, errors, help text, and confirmation output are consistently written in Chinese, including required confirmation wording such as “确认执行”. There is no indication that the skill is region-specific or that users may opt into another language, which can violate a language/locale choice policy.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This code emits every rendered report with `<html lang="zh-CN">`, enforcing a specific language/locale in the generated artifact. The file also contains extensive fixed Chinese user-facing labels and messages, but does not offer any user opt-in or locale selection mechanism.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
This Python file is in scope for natural-language policy checks. The constant `CONFIRMATION_TEXT = "确认执行"` forces a specific language for a required user confirmation, and later validation rejects any other text, which can violate language/locale policy when no user opt-in or justification is provided.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This code rejects any HTML report whose `html.lang` is not exactly `zh-CN`, which is a natural-language/locale constraint. The file does not offer an opt-in choice or document a region-specific justification for forcing this locale, so it matches the policy-violation criterion.

Missing User Warnings

Low
Confidence
84% confidence
Finding
The document explicitly instructs the skill to group paid task `reqId` values into a local `.aidso-geo/tasks/` manifest, but it does not pair that behavior with a clear user-facing warning about local persistence, retention, or where the data lives. While `reqId` values are not API secrets, they are still linkable operational metadata for paid jobs and may expose user activity, prompts, or later enable retrieval workflows if another party gains local access.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
This JSON example uses Chinese labels, titles, and narrative text throughout, but does not state that the report is China-specific or that language is configurable. Under the policy rule, forcing a specific language without opt-in can be a natural-language locale violation.

Natural-Language Policy Violations

Low
Confidence
98% confidence
Finding
This code emits user-facing error and help text in Chinese, such as the API URL validation and token errors, while the file provides no opt-in, fallback, or explanation that the skill is intended only for Chinese-speaking users. That is a natural-language locale policy concern under the rule for forced language without user choice.

Static analysis

No suspicious patterns detected.