Back to skill

Security audit

全国高考志愿填报助手

Security checks for vulnerabilities and agentic risk

Overview

The skill has a clear admissions-query purpose, but it stores API keys in plaintext in a way that can persistently redirect future API calls and expose the key and query data.

Review before installing. Use only a key you are comfortable storing locally, do not paste any multiline or modified API key, keep .env out of source control and backups where possible, and prefer a fixed version that validates keys and locks the API host. Treat 2026 admissions results as simulated preview data and verify final decisions against official admissions sources.

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:45
Finding

Persistent dotenv Injection Can Redirect Authenticated API Requests

Content
View full analysis

Vulnerability Details

File Location: scripts/config.py:45-58, scripts/config.py:61-69; request sink at scripts/call_api.py:49-68
Vulnerability Type: Persistent configuration injection and credential disclosure
Risk Level: Medium

Vulnerable Code

python
# scripts/config.py:45-58
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
python
# scripts/config.py:61-69
def set_api_key(api_key: str) -> bool:
    """设置API key并持久化到.env"""
    if not api_key or not api_key.strip():
        return False
    api_key = api_key.strip()
    if not save_api_key_to_env(api_key):
        return False
    # 更新全局 settings 实例
    settings.api_key = api_key
    return True
python
# scripts/config.py:10-15
model_config = SettingsConfigDict(
    env_prefix="XBY_GAOKAO_",
    env_file=".env",
    env_file_encoding="utf-8",
    extra="ignore",
)
python
# scripts/call_api.py:49-68
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)
...[truncated 2409 chars]
Remediation
View remediation

Remediation Suggestions

  1. Apply strict API-key validation before persistence:

    • Reject \r, \n, NUL, control characters, and unexpected whitespace.
    • Enforce the provider's documented key length and character set.
    • Fail closed when validation is unsuccessful.
  2. Do not build dotenv records through direct string interpolation. Use a dotenv serialization library that safely quotes values, or avoid dotenv persistence for secrets entirely.

  3. Store credentials in an operating-system credential manager or managed secret store. If .env remains necessary:

    • Create it with owner-only permissions such as 0600.
    • Ensure it is excluded from version control.
    • Avoid storing unrelated configurable security boundaries in the same attacker-influenced file.
  4. Prevent endpoint redirection:

    • Make the production API endpoint immutable.
    • Require the https scheme.
    • Enforce an exact hostname allowlist, such as mcp.xiaobenyang.com.
    • Reject URLs containing user information, fragments, unexpected ports, or non-HTTPS schemes.
  5. Add regression tests using keys containing CRLF sequences, dotenv syntax, quotes, Unicode separators, and NUL characters. Verify that invalid values are rejected and cannot alter any XBY_GAOKAO_* setting.

Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (22)

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

This code manually reads the .env file to extract a specific API key, bypassing normal configuration handling and broadening direct secret access within the skill. In context, this is not credential stealing, but it is unnecessary secret handling that increases the chance of accidental leakage, misuse, or insecure future extensions.

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

The existence check is part of a manual credential-reading path that opens and parses .env directly. Although not malicious by itself, this expands secret-handling logic and makes the application more likely to access credentials from disk in ways operators may not expect.

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

The direct read of XBY_APIKEY from the process environment bypasses the declared XBY_GAOKAO_ namespace and contributes to inconsistent secret sourcing. That inconsistency can load the wrong secret unexpectedly and weakens operational control over credential exposure paths.

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

Credential Access

High
Category
Privilege Escalation
Confidence
91% confidence
Finding

This function explicitly persists an API key to a plaintext .env file, creating a durable local copy of the credential. If the host is shared, backed up, inspected by other tools, or the file is accidentally committed, the key can be disclosed and abused to access the upstream service.

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 exposes capabilities that imply access to environment variables, filesystem read/write, and network operations, but it does not declare any explicit tool scope or allowed-tools restrictions. In a skill that also instructs collecting and storing an API key, the lack of scoping increases the blast radius if the implementation is modified, abused, or prompt-injected into using unintended capabilities.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill states that 2026 data is virtualized based on 2025 data, but the description does not clearly warn users that recommendation outputs may therefore be simulated and unsuitable for final decision-making. In an education admissions context, this can mislead users into relying on fabricated or non-official data for high-stakes choices, causing material decision harm even without classic code execution risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This code performs an HTTP POST to an upstream service using user-supplied parameters and includes an API key in headers, but there is no user-facing disclosure, confirmation prompt, or explanatory comment/docstring warning that data will be transmitted externally. For code files, network calls that transmit user or system data should have some visible warning unless clearly disclosed as part of the skill's stated behavior in nearby documentation or messaging, which is not present in this file.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The code adds credential persistence and mutation capability by writing an API key into a local .env file and process environment, which exceeds a simple admissions-data query role and increases secret exposure risk on shared hosts, repos, backups, or logs. While this is likely for convenience rather than abuse, storing secrets in plaintext without clear necessity or boundary checks creates a real security weakness.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The function persists a supplied API key to .env automatically with no user-facing warning, consent, or visibility into retention. This can surprise users and cause credentials to remain on disk longer than intended, where they may be exposed through local access, backups, source-control mistakes, or support bundles.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

The skill name, parameters, examples, and interaction design are all written as China-specific Chinese-language usage, and there is no statement allowing alternative languages or clarifying that the locale restriction is intentional. The policy calls for flagging language or locale constraints when they are effectively forced without opt-in or explicit justification.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The instruction to directly present raw API data encourages unreviewed forwarding of third-party content to users without validation, filtering, or sensitivity checks. If the upstream API returns inaccurate, malicious, or sensitive fields, the assistant could expose that content verbatim, amplifying misinformation or accidental data leakage.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The dependency specifier uses a lower bound only (requests>=2.31.0) rather than pinning an exact version or constrained range. This makes builds non-reproducible and can silently pull in a later vulnerable or breaking release, which is especially relevant because requests has multiple known advisories and the manifest does not prove a safe installed version.

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

The manifest references requests without pinning an exact version, so it is impossible to verify from this file whether deployment will use a version affected by any of the known advisories. In isolation this is a supply-chain hygiene weakness rather than proof of an exploitable bug, but it materially reduces assurance for a network-capable package.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

pydantic>=2.7.0 is unpinned, so different environments may install different versions over time. That increases supply-chain and maintenance risk because a later affected release could be selected without review, and known advisories exist for this package family.

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

Because pydantic is not pinned, the file does not establish whether the installed version is vulnerable to any known advisories. This creates uncertainty in dependency security posture and can allow vulnerable versions into builds if resolution changes over time.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

pydantic-settings>=2.2.0 allows installation of any newer release, preventing deterministic builds. Because this package has at least one known advisory and may interact with secrets/configuration handling, leaving it unpinned can expose the skill to avoidable supply-chain risk.

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

pydantic-settings has a known advisory history, and the unpinned requirement means the actual installed version cannot be verified from the manifest. That uncertainty is meaningful because this package may process sensitive settings and secrets-related paths.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

python-dotenv>=1.0.1 is also unpinned, which means future installs may resolve to different versions with different security properties. Since this package can affect environment/config loading and has known advisories, unconstrained upgrades can create avoidable 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
91% confidence
Finding

The requirement for python-dotenv is not pinned, so a vulnerable release could be installed without that being obvious from the manifest. Given the package's role in environment file handling and its advisory history, this weakens assurance even though no direct exploit is shown here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
71% confidence
Finding

The file contains user-visible natural-language text exclusively in Chinese, including configuration descriptions and status messages, without indicating any language choice or opt-in. Under the stated policy, forcing a specific language without user selection can be a locale-policy issue.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The settings declare an XBY_GAOKAO_ prefix, but the code bypasses that policy and directly reads XBY_APIKEY from .env and the environment. This inconsistency can cause operators to misunderstand where secrets are sourced from, leading to accidental secret loading, misconfiguration, and weaker auditability of credential handling.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.