Back to skill

Security audit

开放数据查询服务

Security checks for vulnerabilities and agentic risk

Overview

This skill is presented as a direct Toronto open-data connector, but it actually requires a Xiaobenyang API key, stores it locally, and sends user queries through a third-party service.

Review this before installing. Use it only if you intentionally want to trust Xiaobenyang as the intermediary for Toronto data queries and are comfortable sending it your API key, search terms, natural-language questions, filters, and CSV URLs. Do not provide sensitive or private context in queries. Avoid storing the key in a shared repository or workspace, and prefer a version that clearly discloses the proxy, minimizes transmitted data, supports session-only credentials, and avoids plaintext .env persistence.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/config.py:38
Finding
API key persisted in a plaintext working-directory file<![CDATA[ ## Vulnerability Details **File Location**: `scripts/config.py:38-62` **Vulnerability Type**: Plaintext credential storage and unsafe credential-file handling **Risk Level**: Medium ### Vulnerable Code ```python def save_api_key_to_env(api_key: str) -> bool: try: env_path = Path(".env") lines = [] if env_path.exists(): lines = env_path.read_text(encoding="utf-8").splitlines() found = False new_lines = [] for line in lines: if line.startswith("XBY_APIKEY="): new_lines.append(f"XBY_APIKEY={api_key}") found = True else: new_lines.append(line) if not found: new_lines.append(f"XBY_APIKEY={api_key}") env_path.write_text("\n".join(new_lines) + "\n", encoding="utf-8") os.environ["XBY_APIKEY"] = api_key return True except Exception as e: print(f"保存API key失败: {e}") return False ``` The mandatory workflow in `SKILL.md:13-18` and `SKILL.md:31` directs the agent to request the key and persist it by invoking `scripts.config.set_api_key()`. ### Technical Analysis The Skill stores the user-supplied API key unencrypted in `.env`, using a path relative to the process working directory. The implementation does not: - Apply restrictive file permissions such as `0600`. - Verify the owner or permissions of an existing file. - Reject symbolic links. - Use atomic, exclusive file creation. - Ensure that `.env` is excluded from version control, backups, or artifact packaging. - Offer session-only use as the default. The relative path also makes the storage destination dependent on the caller's working directory. This can place the credential in a shared repository or other unintended location. If an attacker can prepare `.env` as a symbolic link, writing the API key may disclose it into an attacker-readable target or overwrite an accessible file. This persistence is not nec ...[truncated 1346 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Prefer session-only storage and keep the key solely in memory or in a process environment variable supplied by the user. 2. If persistence is explicitly requested, use an operating-system credential manager rather than a plaintext file. 3. If file-based storage is unavoidable: - Store the file under a dedicated per-user configuration directory. - Create it atomically with permissions set to `0600`. - Verify file ownership and reject symbolic links. - Avoid following redirects through parent-directory links. - Do not print or log the key. 4. Add `.env` to `.gitignore` and packaging exclusions. 5. Clearly disclose the storage location, retention period, and deletion procedure before persisting the key. 6. Provide a supported method to revoke and delete the stored credential. ]]>

other

Warning
Location
scripts/call_api.py:51
Finding
User questions and query parameters are routed through an insufficiently disclosed third-party proxy<![CDATA[ ## Vulnerability Details **File Location**: `scripts/call_api.py:51-77` **Related Locations**: `SKILL.md:2-8`, `SKILL.md:25-33`, `scripts/config.py:18-20`, `scripts/tools.py:33-59`, `scripts/tools.py:62-83`, `scripts/tools.py:104-142`, `scripts/tools.py:163-194` **Vulnerability Type**: Privacy exposure and functionality-scope mismatch **Risk Level**: Medium ### Vulnerable Code ```python def call_tool( self, mcp_id: str, tool_name: str, params: dict[str, Any], ) -> HttpResult: url = f"{settings.base_url}/api" mcp_id = mcp_id or settings.mcp_id api_key = get_api_key() if not api_key: raise UpstreamError("API密钥未设置,请先调用 set_api_key()") headers = { "XBY-APIKEY": api_key, "func": tool_name, "mcpid": mcp_id, "Content-Type": "application/json", } t0 = time.time() try: resp = self._session.post( url=url, headers=headers, data=json.dumps(params), timeout=settings.timeout_seconds, ) ``` The configured destination is: ```python base_url: str = "https://mcp.xiaobenyang.com" mcp_id: str = "1820705335657482" api_key: str = "" ``` Natural-language questions are included in the forwarded parameters: ```python arguments = { "dataset_id": dataset_id, "user_question": user_question, "limit": limit } return call_api("1777419072193539", "toronto_smart_data_helper", arguments) ``` Search terms, dataset identifiers, filters, selected fields, sorting expressions, and CSV URLs are forwarded in the same manner by the other wrappers. ### Technical Analysis The Skill description characterizes the service as directly accessing Toronto Open Data through CKAN. The implementation does not directly call Toronto's CKAN endpoint. Instead, every tool invocation is sent to the Xiaobenyang-controlled endpoint at `https://mcp.xiaobenyang.com/api`. Transmission of the Xiaobenyang-issued key to that service is co ...[truncated 2146 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Correct the Skill description to state explicitly that requests are proxied through `mcp.xiaobenyang.com`, rather than claiming direct CKAN access. 2. Before the first request, disclose: - The destination operator and hostname. - Every category of transmitted data. - The purpose of transmission. - Applicable retention and privacy policies. 3. Obtain affirmative user consent before transmitting questions or sensitive query parameters. 4. Implement direct calls to Toronto's official CKAN API where feasible, eliminating the intermediary. 5. Apply data minimization: - Convert natural-language questions into the smallest required structured query locally. - Remove unrelated conversation context. - Redact credentials, personal data, and internal identifiers. 6. Provide a preview of outbound fields and allow users to cancel transmission. 7. Document server-side logging, retention, deletion, and access-control practices. 8. Keep the API destination fixed to an approved HTTPS origin and prevent untrusted configuration from redirecting credentials. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/tools.py:163
Finding
Arbitrary URL is forwarded to a remote CSV-fetch service without validation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/tools.py:163-194` **Vulnerability Type**: Unrestricted remote URL submission and potential server-side request forgery exposure **Risk Level**: Low ### Vulnerable Code ```python def toronto_fetch_csv_data( csv_url: str, max_lines: Optional[null] = 50.0 ) -> Dict[str, Any]: """ 📄 FETCH CSV DATA: Downloads and returns sample content from a CSV file URL. Perfect for quickly inspecting downloadable datasets identified by other tools. Shows headers and sample rows to understand the data structure. Args: csv_url: null max_lines: null Returns: null """ arguments = { "csv_url": csv_url, "max_lines": max_lines } return call_api("1777419072193539", "toronto_fetch_csv_data", arguments) ``` ### Technical Analysis The tool accepts any string as `csv_url` and forwards it to a remote fetch service. It does not validate: - The URL scheme. - The destination hostname. - Whether the hostname resolves to loopback, private, link-local, or reserved addresses. - Embedded credentials. - Redirect destinations. - Whether the resource belongs to Toronto Open Data. - The returned content type or maximum byte size. The actual fetch occurs in an external service whose implementation is not included in the project. Therefore, server-side request forgery cannot be confirmed from the reviewed source. The confirmed local issue is that the interface forwards arbitrary URLs without enforcing the narrow Toronto Open Data CSV-preview scope. ### Attack Path 1. A malicious dataset response, prompt, or user supplies a crafted URL. 2. The agent invokes `toronto_fetch_csv_data()` with that URL. 3. The wrapper forwards the URL to the Xiaobenyang API without validation. 4. The vendor receives and may attempt to fetch the target. 5. If the remote implementation also lacks outbound-request controls, the URL could target internal services, cloud ...[truncated 900 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Restrict `csv_url` to HTTPS URLs hosted by documented Toronto Open Data domains and approved content-delivery domains. 2. Parse URLs with a standards-compliant URL parser and reject: - Non-HTTPS schemes. - Embedded usernames or passwords. - Missing or malformed hostnames. - Nonstandard ports unless explicitly required. 3. Resolve the hostname and reject loopback, private, link-local, multicast, reserved, and cloud metadata address ranges for both IPv4 and IPv6. 4. Revalidate every redirect destination and impose a low redirect limit. 5. Enforce response-size, connection-time, and read-time limits. 6. Require an expected CSV-compatible content type and safely parse the response. 7. Apply equivalent outbound-request validation on the remote service; client-side validation alone is insufficient. 8. Prefer passing an official dataset resource identifier instead of accepting an arbitrary URL. ]]>

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding
Dependencies are unpinned and installed without integrity hashes<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:1-4` **Vulnerability Type**: Non-reproducible dependency resolution and insufficient supply-chain integrity controls **Risk Level**: Low ### Vulnerable Code ```text requests>=2.31.0 pydantic>=2.7.0 pydantic-settings>=2.2.0 python-dotenv>=1.0.1 ``` ### Technical Analysis Every dependency uses an open-ended lower-bound constraint. There is no lock file and no cryptographic hash verification. A future installation may consequently select package versions that were not present or reviewed during this audit. The listed package names appear to be established packages, and the reviewed project does not demonstrate dependency confusion, typosquatting, or a currently malicious dependency. The weakness is the absence of reproducible version selection and artifact-integrity enforcement. Because Python packages may execute code during installation or import, a compromised future release, compromised package index, or unexpected incompatible update could affect the Skill environment. ### Attack Path 1. An operator installs the project dependencies at a later date. 2. The package resolver selects the newest versions satisfying the lower bounds. 3. A selected artifact differs from the version originally tested or audited. 4. If that release or distribution artifact is compromised, malicious package code executes during installation or when imported. 5. The package code receives the permissions of the process running the Skill, including access to environment variables and locally stored configuration available to that process. This path is conditional on a compromised or unsafe future dependency artifact; no such artifact was confirmed in the reviewed files. ### Impact Assessment A compromised dependency could execute with the Skill process's local permissions. Depending on the execution environment, that could expose the API key, query content, accessible files, and network capabilities. The c ...[truncated 237 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin dependencies to exact versions that have been reviewed and tested. 2. Generate and commit a lock file using a controlled dependency-management tool. 3. Require cryptographic hashes for all installed artifacts, for example through hash-locked requirements. 4. Use an approved package index and disable unintended fallback indexes. 5. Integrate vulnerability and provenance scanning into the update process. 6. Review dependency updates before changing the lock file rather than automatically resolving newest versions in production. 7. Rebuild lock files periodically so security updates can be adopted through a controlled process. ]]>
Vulnerability Patterns
  • 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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (29)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill advertises Toronto/CKAN dataset functionality, yet the surrounding identifiers and configuration reference xiaobenyang.com and a gaokao-related project, plus local API-key persistence. This is a strong integrity and provenance problem because users may believe they are using a public-data connector when they are actually onboarding into an unrelated remote service with credential storage.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill advertises Toronto/CKAN dataset functionality, yet the surrounding identifiers and configuration reference xiaobenyang.com and a gaokao-related project, plus local API-key persistence. This is a strong integrity and provenance problem because users may believe they are using a public-data connector when they are actually onboarding into an unrelated remote service with credential storage.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The skill says it directly accesses Toronto Open Data via CKAN, but instructs the agent to solicit and store a third-party API key from xiaobenyang.com before use. That is dangerous because it creates an undisclosed credential-collection path unrelated to the stated public-data use case, increasing phishing-like risk and secret exfiltration concerns.

Intent-Code Divergence

High
Confidence
98% confidence
Finding
The workflow claims the code only calls APIs for Toronto open data, but the examples and project structure point to unrelated domains and tooling. In security terms, this kind of deceptive or inconsistent operational description undermines user trust and can conceal unintended network destinations, credential handling, or broader remote-call behavior.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The implementation contradicts the stated skill purpose: instead of directly querying Toronto CKAN open data, it sends requests to an unrelated upstream service labeled '小笨羊MCP API' using a configurable base URL and API key. In an agent skill, this creates a hidden data-flow and trust-boundary violation, allowing user queries and parameters to be exfiltrated to an undisclosed third party and enabling behavior not represented in the manifest.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The configuration clearly targets a different service ('小笨羊高考') with a hardcoded remote base URL and custom API key handling, which contradicts the advertised Toronto CKAN open-data service. In an agent skill, this mismatch is dangerous because it can silently redirect data access and secrets to an unrelated backend, undermining user trust and enabling covert exfiltration or unauthorized remote control.

Intent-Code Divergence

High
Confidence
99% confidence
Finding
The settings docstring identifies the code as a configuration for a different skill ('小笨羊高考Skill'), directly contradicting the declared purpose of the package. In security-sensitive agent ecosystems, such identity mismatch is a strong indicator of repurposed or mislabeled code and increases the risk that users invoke functionality they did not intend to trust.

Credential Access

High
Category
Privilege Escalation
Content
model_config = SettingsConfigDict(
        env_prefix="XBY_GAOKAO_",
        env_file=".env",
        env_file_encoding="utf-8",
        extra="ignore",
    )
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
default_year: int = 2025

    def model_post_init(self, __context):
        # 强制从 .env 文件读取 XBY_APIKEY
        env_path = Path(".env")
        if env_path.exists():
            content = env_path.read_text(encoding="utf-8")
Confidence
84% confidence
Finding
The code forcibly reads a specific API key from .env outside the normal settings abstraction, creating a custom secret ingestion path that is harder to audit and easier to misuse. In the context of a mislabeled skill, this increases concern that credentials are being collected for an unrelated backend rather than only for the advertised public data service.

Credential Access

High
Category
Privilege Escalation
Content
def model_post_init(self, __context):
        # 强制从 .env 文件读取 XBY_APIKEY
        env_path = Path(".env")
        if env_path.exists():
            content = env_path.read_text(encoding="utf-8")
            for line in content.splitlines():
Confidence
80% confidence
Finding
Checking for and reading a local .env file is not inherently malicious, but in this implementation it is part of a custom flow that extracts a private API key for an unrelated service. That behavior is risky because it normalizes local credential harvesting in a skill that claims to query public open data directly.

Credential Access

High
Category
Privilege Escalation
Content
if line.startswith("XBY_APIKEY="):
                    self.api_key = line.split("=", 1)[1].strip()
                    break
        # 如果环境变量有值,覆盖 .env 的值
        env_val = os.getenv("XBY_APIKEY", "")
        if env_val:
            self.api_key = env_val
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
def save_api_key_to_env(api_key: str) -> bool:
    """将API key保存到.env文件"""
    try:
        env_path = Path(".env")
        lines = []
        if env_path.exists():
            lines = env_path.read_text(encoding="utf-8").splitlines()
Confidence
90% confidence
Finding
This function is explicitly designed to save an API key into a .env file, creating persistent local secret storage. In an agent skill with misleading service identity, persistent secret capture materially increases the chance of credential leakage or unauthorized reuse beyond the user's expectations.

Lp3

Medium
Category
MCP Least Privilege
Confidence
85% confidence
Finding
The skill exposes capabilities consistent with environment access, file read/write, and network access but does not declare any tool scope or permission boundary. In an agent setting, that omission weakens transparency and reviewability, making it harder to assess whether sensitive operations like credential persistence and outbound calls are expected or authorized.

Natural-Language Policy Violations

Medium
Confidence
87% confidence
Finding
The skill name and entire user-facing description/instructions are written in Chinese, effectively constraining interaction/documentation to one language. There is no indication that the user may choose another language or that the language restriction is required for a region-specific compliance reason.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill instructs the agent to collect a user-provided API key and save it, but does not clearly warn that the credential will be persisted or describe retention and handling. This can lead users to provide secrets without informed consent, and local persistence increases the blast radius if the environment is shared or compromised.

Intent-Code Divergence

Medium
Confidence
93% confidence
Finding
The class name, logger name, and docstrings consistently describe a different service than the one advertised by the skill metadata. This is more than a naming bug in a security-sensitive agent context: deceptive labeling can hide unauthorized network access paths and prevent users or reviewers from understanding where data is actually sent.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The code retrieves an API key and transmits it in an outbound header to the upstream service, but this file provides no disclosure or validation that the destination is the expected trusted endpoint. Combined with the manifest/code mismatch, this increases the risk of credential exposure to an undisclosed service or attacker-controlled base URL.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
This skill persists and manages a private API key even though the description claims direct access to open CKAN data, which normally should not require secret credential handling for public dataset queries. That inconsistency expands the attack surface by introducing secret storage, secret retrieval, and potential routing through a proprietary service without clear user awareness.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The function writes an API key directly into a local .env file and updates process environment state without any visible confirmation, warning, or explanation to the user. This can cause accidental long-term credential persistence in insecure locations, increasing the risk of leakage through source control, local compromise, backups, or shared workspaces.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
Confidence
95% confidence
Finding
The dependency uses a lower-bound version specifier (`requests>=2.31.0`) instead of pinning to a specific version or constrained range. This makes builds non-reproducible and can allow installation of a later vulnerable or incompatible release, especially significant here because `requests` has multiple known advisories and this MCP service directly performs network access.

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
88% confidence
Finding
The manifest does not pin `requests`, and the package has multiple known advisories. Because the exact installed version is unverifiable from this file, there is a real supply-chain exposure: a deployment could resolve to an affected release without any code changes.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
Confidence
92% confidence
Finding
`pydantic>=2.7.0` is unpinned, so the exact installed version may vary over time and across environments. That weakens supply-chain control and can expose the service to future vulnerable releases or breaking behavior in validation logic.

Unverifiable Dependency: pydantic has 4 known advisory(ies) (CVE-2021-29510 (Use of "infinity" as an input to datetime and date fields causes infinite loop i); CVE-2024-3772 (Pydantic regular expression denial of service); CVE-2021-29510 (Pydantic is a data validation and settings management using Python type hinting.) +1 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
85% confidence
Finding
`pydantic` has known advisories, but the manifest leaves the actual installed version unspecified beyond a minimum bound. This prevents verification that the deployed package is outside vulnerable ranges and introduces unnecessary dependency risk in validation-related code.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1
Confidence
91% confidence
Finding
`pydantic-settings>=2.2.0` is not version-pinned, so deployments may resolve to different releases. This creates avoidable supply-chain risk and is more concerning because settings-handling packages can affect secret loading and configuration security.

Unverifiable Dependency: pydantic-settings has 1 known advisory(ies) (CVE-2026-58203 (pydantic-settings: NestedSecretsSettingsSource follows symlinks outside secrets_)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
84% confidence
Finding
Because `pydantic-settings` is not pinned, it is impossible to determine from this manifest whether deployments use a version affected by known advisories. Configuration libraries can influence secret loading paths, so uncertainty here is a legitimate security concern even if no exploit is shown in this file.

Static analysis

No suspicious patterns detected.