Back to skill

Security audit

CPAN包信息服务

Security checks for vulnerabilities and agentic risk

Overview

This skill advertises CPAN package lookup, but it requires and stores a XiaoBenYang API key and sends credentialed requests through a separate configurable service.

Review this carefully before installing. The main risk is not destructive code; it is that a CPAN-looking skill asks for a XiaoBenYang API key, stores it in plaintext in .env, and can send it to a configurable API origin. Install only if you understand and trust that backend, are comfortable with local plaintext credential storage, and can rotate the key if exposed.

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

Warning
Location
scripts/config.py:42
Finding
API Key Persisted in a Plaintext Working-Directory File<![CDATA[ ## Vulnerability Details **File Location**: `scripts/config.py:42-59` **Vulnerability Type**: Plaintext sensitive-data storage **Risk Level**: Medium ### Vulnerable Code ```python 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() 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 ``` ### Technical Analysis The API key is written without encryption to a relative `.env` file in the current working directory. The implementation does not explicitly create the file with owner-only permissions or verify the permissions of an existing file. Its effective access controls therefore depend on the process umask, existing file permissions, directory permissions, and deployment environment. Using a relative path also means the credential location depends on the directory from which the process is started. This may cause the key to be stored in an unintended shared directory, included in a backup or source archive, or exposed to other local users and processes. ### Attack Path 1. A user supplies an API key as required by the Skill. 2. `set_api_key()` invokes `save_api_key_to_env()`. 3. The function writes the key as `XBY_APIKEY=<secret>` to `.env` in the current working directory. 4. An attacker with read access to that directory or file reads the plaintext key. 5. The attacke ...[truncated 628 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Prefer an operating-system secret manager, container secret mount, or session-only in-memory credential instead of persistent plaintext storage. 2. If file persistence is unavoidable, use a fixed, Skill-specific configuration directory rather than the current working directory. 3. Create the secret file atomically with owner-only permissions such as `0600`, and verify or correct the permissions of an existing file before writing. 4. Ensure `.env` is excluded from version control, build artifacts, diagnostic bundles, and backups that do not require the credential. 5. Document credential rotation and immediately revoke keys suspected of exposure. 6. Avoid returning or logging the key in exception details, diagnostics, or user-facing output. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/call_api.py:52
Finding
Environment-Configurable API Origin Can Redirect Credential-Bearing Requests<![CDATA[ ## Vulnerability Details **File Locations**: `scripts/config.py:9-19`; `scripts/call_api.py:52-72` **Vulnerability Type**: Credential disclosure through an insufficiently constrained service endpoint **Risk Level**: Medium ### Vulnerable Code ```python class Settings(BaseSettings): """小笨羊高考Skill配置""" model_config = SettingsConfigDict( env_prefix="XBY_GAOKAO_", env_file=".env", env_file_encoding="utf-8", extra="ignore", ) # API配置 base_url: str = "https://mcp.xiaobenyang.com" mcp_id: str = "1820705335657482" api_key: str = "" ``` ```python 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", } # data = {k: str(v) if v is not None else "" for k, v in params.items()} t0 = time.time() try: resp = self._session.post( url=url, headers=headers, data=json.dumps(params), timeout=settings.timeout_seconds, ) ``` ### Technical Analysis `Settings` uses the `XBY_GAOKAO_` environment-variable prefix, allowing `base_url` to be overridden through configuration such as `XBY_GAOKAO_BASE_URL`. The client constructs the request URL from that value and unconditionally adds the `XBY-APIKEY` credential to the request headers. There is no validation requiring HTTPS or restricting the destination hostname to the intended XiaoBenYang service. Consequently, a party capable of influencing the process environment or its settings source can redirect credential-bearing requests to an attacker-controlled endpoint. A non-HTTPS override could additionally expose the credential t ...[truncated 1082 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Keep the credential-bearing API origin immutable unless endpoint customization is an explicit operational requirement. 2. Before adding the API key, parse the URL and require: - The `https` scheme. - An exact approved hostname, such as `mcp.xiaobenyang.com`. - An approved port. - No embedded user information. 3. Apply the hostname check again after redirects, or disable redirects for authenticated requests unless every redirect target is independently allowlisted. 4. Separate development endpoint overrides from production configuration, and never attach production credentials to non-production origins. 5. Protect environment and `.env` configuration sources with least-privilege filesystem and deployment controls. 6. Rotate the API key if requests may already have been sent to an untrusted endpoint. ]]>
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 (27)

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared purpose is CPAN metadata retrieval, but the skill also instructs reading/writing a local .env file, persisting API keys, and managing a service apparently related to '小笨羊高考'. This creates a deceptive trust boundary: users may expose credentials or permit local state changes under the false assumption that the skill is a simple public-data fetcher.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared purpose is CPAN metadata retrieval, but the skill also instructs reading/writing a local .env file, persisting API keys, and managing a service apparently related to '小笨羊高考'. This creates a deceptive trust boundary: users may expose credentials or permit local state changes under the false assumption that the skill is a simple public-data fetcher.

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
93% confidence
Finding
The post-init hook forcibly reads .env and extracts XBY_APIKEY manually, bypassing the normal settings abstraction and expanding direct secret-file access. In a skill that should only provide CPAN package information, this unnecessary credential scraping increases exposure and suggests hidden or unrelated functionality.

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
93% confidence
Finding
This line initiates direct access to the .env file for secret retrieval, contributing to unnecessary credential-file handling outside the framework's normal controls. Direct file reads make it easier to expand secret collection behavior and harder to audit than standard configuration loading.

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
97% confidence
Finding
This function is explicitly designed to persist an API key into a .env file, creating durable local secret storage that may be exposed through source control, backups, shared environments, or permissive file access. In the context of a CPAN metadata service, durable credential storage is unusually dangerous because it is not obviously necessary for the advertised feature set and may indicate undeclared external service use.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill declares no explicit tool scope or permissions while its documented/project capabilities imply environment access, file read/write, and network access. In an agent setting, missing scope boundaries increases the chance of over-privileged execution and makes it harder to enforce least privilege.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The skill name and surrounding documentation are presented as Chinese-only instructions, and the workflow does not offer the user any language or locale choice. Under the policy, forcing a specific language without opt-in is a natural-language policy concern unless the locale restriction is explicitly justified.

Intent-Code Divergence

Medium
Confidence
91% confidence
Finding
Requiring API key acquisition from an unrelated site conflicts with the stated CPAN-focused purpose and signals that the documented data source is not what users are told. This can mislead users into disclosing credentials to support access to a different backend than expected.

Ssd 3

Medium
Confidence
96% confidence
Finding
The skill explicitly instructs the model to ask the user for an API key and then persist it via code. Collecting secrets through natural-language interaction and writing them to local configuration increases the risk of credential exposure in chat logs, prompt traces, local files, or downstream tool misuse.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
Contradictory workflow and project-structure documentation undermines operator understanding of what the skill actually does. In security-sensitive agent environments, such inconsistency can conceal overbroad behavior, lead to unsafe approvals, and make review and monitoring less effective.

Ssd 3

Medium
Confidence
92% confidence
Finding
The instruction to directly present raw API data to the user bypasses any safety filtering, minimization, or schema validation. If the upstream API returns secrets, internal identifiers, error traces, or unexpected sensitive fields, the model is directed to disclose them verbatim.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
This code embeds user-facing natural-language strings only in Chinese, including the class/function docstrings and the missing-API-key error message. Under the policy, forcing a specific language without opt-in or a documented region-specific justification is a natural-language policy violation.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The class docstring identifies a different skill ("小笨羊高考Skill配置") than the manifested CPAN package information service, indicating copied or repurposed code. Such provenance mismatches are a supply-chain red flag because they can hide undeclared behavior, confuse reviewers, and suggest the credential-handling logic may not belong in this skill at all.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The module provides functions to persist, mutate, and globally expose an API key in a local .env file even though the declared skill purpose is only CPAN package information retrieval. Persisting credentials to disk increases the chance of accidental disclosure through source control, backups, logs, or other local users, and the mismatch in stated functionality raises suspicion about unnecessary secret handling.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The code saves the API key directly into .env without any user-facing warning, consent flow, or safeguards. Silent credential persistence can surprise users and cause secrets to be exposed via repository commits, local inspection, debugging artifacts, or insecure workstation setups.

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
96% confidence
Finding
The dependency specification uses a lower-bound only version constraint for requests, which makes builds non-reproducible and can unexpectedly pull in vulnerable or breaking upstream releases. In a network-facing MCP server, this increases supply-chain and patch-management risk because the actual installed version cannot be reliably audited or reproduced.

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
89% confidence
Finding
requests has known historical advisories, and because the manifest does not pin a concrete version, there is no way to verify whether deployments are using an affected release. For a service that retrieves remote package information, this matters more than in an offline tool because HTTP handling is part of the core trust boundary.

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 pydantic dependency is not pinned to an exact version, so installations may resolve to different releases over time. That weakens reproducibility and can introduce vulnerable or incompatible versions without any code change in the skill itself.

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 published advisories, but the current requirement does not identify the exact installed release, so exposure cannot be determined. This is a real supply-chain hygiene issue because validation libraries often process untrusted input and can become attack surfaces when vulnerable versions are resolved.

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
94% confidence
Finding
Using an open-ended minimum version for pydantic-settings means future installs may consume unexpected upstream changes or affected releases. Because this package often influences configuration loading, version drift can create security and reliability issues that are hard to trace.

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
83% confidence
Finding
The manifest leaves pydantic-settings unresolved beyond a minimum version while known advisories exist for the package, so the actual security posture of installations cannot be established. Because configuration and secrets handling may be involved, uncertainty around the resolved version is a meaningful risk even if no exploit is shown here.

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
94% confidence
Finding
python-dotenv is specified with only a minimum version, allowing uncontrolled upgrades and making the runtime dependency set unverifiable. Since dotenv libraries can affect secret and environment loading, unresolved version drift may expose the application to upstream security flaws or unsafe behavior changes.

Static analysis

No suspicious patterns detected.