Back to skill

Security audit

万智牌卡牌查询服务

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly performs Magic: The Gathering API lookups, but it requires collecting and persistently storing an API key in a local plaintext .env file and contains mismatched leftover school-search documentation.

Review before installing. Only use this skill if you are comfortable giving it a XiaoBenYang API key, sending card queries and that key to the XiaoBenYang API, and having the key stored in a plaintext .env file in the working directory. Prefer a disposable or limited-scope API key, keep .env out of version control, and rotate the key if it may have been 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 (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/config.py:46
Finding

API Key Persisted in Plaintext Without File Security Controls

Content
View full analysis

Vulnerability Details

File Location: scripts/config.py, lines 46-64
Vulnerability Type: Insecure sensitive-data storage and unsafe file handling
Risk Level: Medium

The application persists the supplied API key in a plaintext .env file located in the process's current working directory.

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

Path(".env") resolves relative to the current working directory rather than a fixed, application-controlled configuration directory. The function writes the API key as an unencrypted XBY_APIKEY value and does not:

  • Enforce owner-only file permissions.
  • Check whether .env is a symbolic link.
  • Verify that the destination is a regular file.
  • Use atomic file creation or replacement.
  • Prevent the file from being placed in a version-controlled directory.

File permissions created by Path.write_text() depend on the process umask. Under a permissive environment, the resulting file may be readable by other local users or processes. If an attacker can prepare the working directory, a malicious .env symbolic link could redirect the write to another file accessible ...[truncated 1766 chars]

Remediation
View remediation

Remediation Suggestions

  1. Avoid persistent storage by default. Keep the API key in a session-scoped environment variable or use the host platform's secret-management facility.
  2. If persistence is necessary, use an operating-system credential store such as Keychain, Credential Manager, Secret Service, or an appropriately configured external secret manager.
  3. Store configuration in a fixed, user-private directory rather than the current working directory.
  4. Create the file atomically with owner-only permissions such as 0600; validate permissions after creation.
  5. Reject symbolic links and non-regular files before reading or writing the destination. Where supported, use no-follow filesystem flags.
  6. Avoid read-modify-write operations on a predictable shared path. Write to a securely created temporary file in the same private directory and atomically replace the destination.
  7. Ensure .env is excluded from version control, packaging, logs, backups, and diagnostic output.
  8. Document key rotation and revocation procedures so users can invalidate credentials after suspected exposure.
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 (28)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The documented purpose is MTG card lookup, but the behavior and references point to unrelated gaokao/school-search components and local secret persistence. This mismatch is dangerous because users and orchestrators may grant trust and permissions based on the declared benign purpose while the skill actually exercises different sensitive capabilities.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/config.py (reported line 13)May include surrounding context.

python
model_config = SettingsConfigDict(
        env_prefix="XBY_GAOKAO_",
        env_file=".env",
        env_file_encoding="utf-8",
        extra="ignore",
    )

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

This code manually opens and parses .env to extract XBY_APIKEY, bypassing the normal settings abstraction and directly handling credentials in plaintext. In context, that increases exposure of secrets and suggests the skill is intentionally managing credentials beyond its stated query-only purpose.

Content

Scanner excerpt · scripts/config.py (reported line 31)May include surrounding context.

python
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")

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

The existence check and direct read of .env are part of a custom credential access path that reads secrets from local plaintext storage. While local config loading is not always malicious, in this skill it is unnecessary and broadens the chance of mishandled credentials.

Content

Scanner excerpt · scripts/config.py (reported line 32)May include surrounding context.

python
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():

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/config.py (reported line 39)May include surrounding context.

python
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

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code persists an API key to a local .env file and also mirrors it into the process environment, creating a durable secret store in a skill whose stated purpose is only card lookup/search. That expands the trust boundary unnecessarily: local plaintext storage increases the chance of credential exposure via source-control mistakes, backups, logs, or other local file reads.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
94% confidence
Finding

This function is explicitly designed to save an API key into a local .env file, creating persistent plaintext credential storage. In a card-query service, that behavior is more dangerous because it is unrelated to the declared functionality and can surprise users by retaining secrets on disk where they may later be exposed.

Content

Scanner excerpt · scripts/config.py (reported line 48)May include surrounding context.

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

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill declares no explicit tool scope or allowed-tools despite documenting capabilities that involve environment access, local file read/write, and network calls. In an agent setting, missing scope boundaries increases the chance of unintended or over-privileged tool use, especially because the skill also instructs persistence of secrets into local configuration.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill claims to provide only MTG query/search but also exposes an unrelated image-generation feature. Hidden or undeclared functionality expands attack surface and can lead to misuse, unexpected content generation, or additional data handling beyond what a user reasonably consented to.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The description states the service provides Chinese card information, and later parameters default to prioritizing Chinese cards. This establishes a language preference as the default behavior, but the file does not explicitly offer users a language or locale choice or document a justified region-specific constraint.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill instructs the model to ask the user for an API key and persist it via local configuration, but does not clearly warn the user that the secret will be stored. This undermines informed consent and increases the risk of credential leakage through local files, later tool access, backups, or logs.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The workflow examples and project structure reference a gaokao/school-search scenario rather than MTG lookup, indicating copy-paste drift or repurposed code. This inconsistency makes it harder to verify intended behavior and raises the risk that unrelated endpoints, parameters, or logic are still present and may process unexpected data.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The documentation explicitly instructs the model to call a school-search function instead of an MTG function. In practice, this can misroute user requests to unrelated tools or services, causing unintended data exposure, incorrect network calls, or execution of capabilities outside the user's expectation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This code retrieves a credential via get_api_key() and sends it in the XBY-APIKEY header during an outbound network request. Although the file contains internal logging for errors and success, there is no user-facing warning, confirmation, or explanatory comment/docstring disclosing that sensitive credentials and request data will be transmitted upstream.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The manifest says this skill is a '万智牌卡牌查询服务', but the primary settings class is documented as configuration for '小笨羊高考Skill'. That is an active intent mismatch in code documentation, suggesting the file was repurposed from another skill and no longer accurately describes its function.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The function silently writes the supplied API key into .env with no user-facing disclosure or confirmation. This is dangerous because users may believe they are supplying a transient token while the software actually creates long-lived plaintext credential storage on disk.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The manifest description limits the skill to querying and searching Chinese Magic card information. The hzls function instead invokes an API to compose an image from card artwork and arbitrary input text, which is a distinct content-generation feature rather than card information retrieval.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency is specified with a lower-bound range instead of an exact pinned version, which makes builds non-reproducible and can cause deployment of unexpectedly vulnerable or incompatible releases over time. Because this service likely makes outbound HTTP requests, allowing an unpinned requests version increases supply-chain uncertainty and complicates verification against known advisories.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1

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 that package has multiple known advisories across its version history, so the actual deployed version may be vulnerable without any way to verify from this file. In an MCP service that likely performs network requests, this ambiguity is security-relevant because HTTP client flaws can affect credential handling, TLS, redirects, and request processing.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
93% confidence
Finding

Using pydantic>=2.7.0 permits any newer release, so future installations may resolve to versions with undiscovered flaws or breaking behavior. This is a real supply-chain hygiene issue even though the line does not itself prove exploitation, because the exact installed version cannot be audited from the manifest alone.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1

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
84% confidence
Finding

Because pydantic is unpinned and has known advisories in some releases, the manifest does not allow verification that installed environments are using a safe version. This creates an auditable supply-chain gap, especially for a service that likely validates external input where parser or regex-related flaws may matter.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
92% confidence
Finding

pydantic-settings>=2.2.0 is unpinned, so environments can install materially different releases without any manifest change. For a service that likely loads configuration and secrets, this weakens assurance around dependency behavior and exposure to future vulnerable versions.

Content

Scanner excerpt · requirements.txt (reported line 3)May include surrounding context.

text
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1

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

pydantic-settings has at least one known advisory in its version history, and the unpinned specifier prevents determining whether the deployed version is affected. Given that settings libraries may load secrets and configuration from the filesystem, unverifiable versions can increase risk if vulnerable behavior is present in a resolved release.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

python-dotenv>=1.0.1 allows unconstrained newer versions, making builds non-deterministic and potentially pulling in vulnerable or behavior-changing releases. Since dotenv libraries often interact with local configuration files and environment handling, lack of pinning increases supply-chain and operational risk.

Content

Scanner excerpt · requirements.txt (reported line 4)May include surrounding context.

text
requests>=2.31.0
pydantic>=2.7.0
pydantic-settings>=2.2.0
python-dotenv>=1.0.1

Unverifiable Dependency: python-dotenv has 2 known advisory(ies) (CVE-2026-28684 (python-dotenv: Symlink following in set_key allows arbitrary file overwrite via ); CVE-2026-28684 (python-dotenv reads key-value pairs from a .env file and can set them as environ)), 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

The manifest leaves python-dotenv unpinned despite known advisories affecting some versions, so it is impossible to confirm whether installations are safe. Since dotenv tooling can read from or write to environment files, unresolved vulnerable versions could affect local file handling and secret management behavior.

Content

No source excerpt is available for this finding.