Back to skill

Security audit

模板搜索服务

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to be a template-search integration, but it stores an API key in a local plaintext .env file and can send that key to a configurable API endpoint.

Review this before installing. Only use it if you trust the XiaoBenYang service and are comfortable storing the API key in a local .env file. Avoid using it in a shared or repository working directory, check that .env does not contain an unexpected XBY_GAOKAO_BASE_URL, and prefer a scoped/revocable API key.

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

Error
Location
scripts/call_api.py:47
Finding
Configurable API Endpoint Allows API Key Exfiltration## Vulnerability Details **File Location**: `scripts/config.py:10-16`, `scripts/config.py:44-65`, and `scripts/call_api.py:47-69` **Vulnerability Type**: Unrestricted API endpoint override and plaintext credential storage **Risk Level**: High ### Vulnerable Code `scripts/config.py:10-16`: ```python model_config = SettingsConfigDict( env_prefix="XBY_GAOKAO_", env_file=".env", env_file_encoding="utf-8", extra="ignore", ) # API configuration base_url: str = "https://mcp.xiaobenyang.com" mcp_id: str = "1820705335657482" api_key: str = "" ``` `scripts/config.py:44-65`: ```python def save_api_key_to_env(api_key: str) -> bool: """Save API key to the .env file.""" 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"Failed to save API key: {e}") return False ``` `scripts/call_api.py:47-69`: ```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 key is not configured; call set_api_key() first") 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=header ...[truncated 2718 chars]
Remediation
## Remediation Suggestions 1. Remove runtime endpoint configurability if it is not required. Use a constant trusted API origin: ```python API_ORIGIN = "https://mcp.xiaobenyang.com" ``` 2. If endpoint configuration is required, validate it before every credential-bearing request: - Require the `https` scheme. - Require an explicit allowlist of trusted hostnames. - Reject embedded credentials, unexpected ports, fragments, and malformed URLs. - Resolve redirects carefully and prevent redirects to untrusted origins. 3. Do not load security-sensitive endpoint configuration from an untrusted working-directory `.env` file. Use a configuration file with verified ownership and restrictive permissions, or obtain the endpoint from trusted deployment configuration. 4. Store API keys in an operating-system credential manager or dedicated secret-management service. If file storage is unavoidable, create the file atomically with owner-only permissions such as `0600`, verify ownership before reading it, and avoid preserving attacker-controlled configuration entries. 5. Separate secret storage from general application configuration so saving an API key cannot activate or preserve an untrusted endpoint override. 6. Add tests confirming that: - HTTP endpoints are rejected. - Non-allowlisted hosts are rejected. - Credentials are never forwarded during cross-origin redirects. - Secret files have restrictive permissions. - Malicious `.env` endpoint overrides cannot change the credential destination.
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 (25)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared purpose is epub360 template search, but the skill behavior includes reading and persisting API keys in local files and references an apparently different project/domain ('xiaobenyang_gaokao_skill'). This mismatch is dangerous because users and reviewers may authorize a benign-seeming search skill without realizing it performs credential handling and may be repurposed code with unclear external data flows.

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
88% confidence
Finding
The post-init hook explicitly reads .env and extracts a specific API key, bypassing normal settings handling and creating custom secret-processing logic. In the context of a template search assistant, this is more suspicious because the skill does not obviously need to scrape and manage local credentials directly, increasing the risk of secret misuse or overcollection.

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
88% confidence
Finding
This line opens the local .env file and reads its full contents to locate an API key. Reading a secret-bearing file directly expands the attack surface and can normalize indiscriminate credential access in a skill whose declared function is unrelated to secret management.

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
94% confidence
Finding
This function is dedicated to saving an API key into .env on disk, creating durable local storage of a sensitive credential. Persisting secrets in a project-local plaintext file materially raises the risk of credential disclosure via source control, local compromise, backups, or accidental sharing; in a template-search skill context, that behavior is more dangerous because it exceeds the minimally expected functionality.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill requests capabilities equivalent to environment access, file read/write, and network use, but does not declare any explicit tool scope or permission boundaries. That makes the operational trust boundary opaque: a user may think this is only a template search skill while it can also read local configuration and persist secrets, increasing the risk of overbroad access or misuse.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The entire skill is presented only in Chinese and provides no indication that users may choose another language or locale. Under the language/locale policy rule, forcing a specific language without user opt-in is a policy concern unless the restriction is explicitly documented and justified as region-specific.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill explicitly instructs the agent to ask the user for an API key and persist it via `set_api_key(api_key)` without explaining storage duration, location, access controls, or safer alternatives. Collecting secrets through conversational flow and writing them to local configuration can expose credentials to logs, other skills, or later unintended reuse if the environment is shared or insufficiently isolated.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The documentation tells the model to call an example function for school search (`search_schools`) even though the skill is supposed to perform template search. In an agentic setting, such mismatched routing instructions can cause unintended tool invocation, parameter confusion, or disclosure of data to the wrong backend, especially when combined with broad tool/network capabilities.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
This code retrieves a credential via get_api_key() and sends it in the XBY-APIKEY header on every POST request. Although the function has docstrings and logs request status, there is no user-facing warning, confirmation, or explanatory comment disclosing that a secret and request parameters will be transmitted to an external service.

Description-Behavior Mismatch

Medium
Confidence
89% confidence
Finding
The module includes functionality to persist and mutate an API credential in a local .env file even though the stated skill purpose is template search. Storing secrets to disk increases exposure through source tree leakage, backups, logs, multi-user hosts, or accidental inclusion in version control, and the persistence behavior is not clearly disclosed by the code shown.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The code writes the provided API key into .env without any visible warning, consent flow, or disclosure to the operator. Silent persistence of credentials is risky because users may assume a transient configuration change while the secret remains on disk and can later be exposed through local compromise or repository mistakes.

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 is specified with a lower-bound only (requests>=2.31.0), which allows future installs to resolve to different versions over time. This weakens reproducibility and can unintentionally pull in vulnerable or breaking releases, especially significant here because requests has multiple known advisories and the exact installed version cannot be verified from this manifest alone.

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 references requests without pinning an exact version, while the package has numerous published advisories. This does not prove an exploitable vulnerable version is currently installed, but it is still a real supply-chain risk because the dependency version cannot be verified or audited from the file.

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
Using pydantic>=2.7.0 without an exact pin makes builds non-reproducible and prevents auditors from determining which version will actually be installed. Because pydantic has known advisories, this ambiguity can result in deployment of an affected release or later-introduced vulnerable version.

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
86% confidence
Finding
Because pydantic is unpinned and has known advisories, the manifest cannot establish whether the eventual installed version is safe. In a service skill that likely processes external input and configuration, unresolved dependency versions increase the chance of shipping a vulnerable parser or validator release.

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
The pydantic-settings dependency is not pinned, so installations may resolve to different versions across environments or over time. This creates supply-chain and patch-management uncertainty, and is more concerning because the package has at least one known advisory that cannot be ruled out from the manifest.

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
pydantic-settings has a known advisory, and the lack of version pinning prevents verification that deployments avoid the affected release. Given this package often handles configuration and secrets sources, uncertainty around its version can have security consequences if vulnerable behavior is introduced.

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>=1.0.1 allows unbounded future versions and does not guarantee deterministic installs. Since the package has known advisories, the lack of pinning makes it impossible to confirm whether a deployed environment is using a safe release.

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 does not pin python-dotenv, despite known advisories affecting the package. Since dotenv libraries interact with environment files and sometimes filesystem paths, an unverifiable version leaves open the possibility of deploying a release with file-handling flaws.

Natural-Language Policy Violations

Low
Confidence
72% confidence
Finding
Natural-language strings and docstrings in the client are exclusively Chinese, including user-facing error text such as the missing API key message. Under the policy, forcing a specific language without user opt-in or documented regional justification can be a locale-policy violation.

Intent-Code Divergence

Low
Confidence
97% confidence
Finding
The skill manifest identifies this skill as '模板搜索服务', but the primary configuration class is documented as configuration for a different '高考' skill. This indicates copied or stale documentation that contradicts the current skill identity and obscures developer intent.

Natural-Language Policy Violations

Low
Confidence
82% confidence
Finding
The natural-language descriptions and visible error/output strings are exclusively in Chinese, which indicates a fixed language choice in the skill experience. There is no indication that the user can choose a language or that the locale restriction is explicitly documented as intentional and region-specific.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The docstring is written entirely in Chinese and presents the skill behavior and parameters only in that language. This creates a language/locale restriction in the skill's natural-language interface without offering the user a choice or documenting that the skill is intentionally region-specific.

Static analysis

No suspicious patterns detected.