Back to skill

Security audit

电影搜索工具

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a movie/TV search wrapper, but it asks for an API key and persists it in a local plaintext .env file with stale mismatched documentation and weak scoping.

Install only if you are comfortable giving this publisher an API key for xiaobenyang.com and having that key stored in a plaintext .env file in the working directory. Prefer using a throwaway or restricted API key, check that .env is private and excluded from version control, and remove or rotate the key after use. The stale gaokao and school-search references should be corrected before broad distribution.

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

API Key Stored Persistently in a Plaintext .env File Without Permission Hardening

Content
View full analysis

Vulnerability Details

File Location: scripts/config.py, lines 44–61
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

Technical Analysis

The function persistently writes a user-supplied API key in plaintext to a relative .env file in the process working directory. It does not explicitly restrict file permissions, verify that the destination is private, reject symbolic links, or perform an atomic secure write.

The project instructions require users to provide this key and direct the agent to persist it through scripts.config.set_api_key(). Consequently, sensitive-data persistence is part of the expected workflow rather than an exceptional operation.

Security exposure depends on the runtime environment and its default file-creation mask. If the resulting file is readable by other local users or processes, stored in a shared directory, included in a backup, or accidentally committed to source control, the API key can be disclosed. Use of a relative path also means the destination changes according to the caller's working directory.

No evidence was found that the project deliberately exfiltrates the key to an unrelated destination. The key is used as the XBY-APIKEY header when c ...[truncated 1571 chars]

Remediation
View remediation

Remediation Suggestions

  1. Prefer nonpersistent, session-scoped credential delivery through the process environment or a dedicated secret-management service.
  2. If persistence is necessary, obtain explicit user consent and store the key in an operating-system credential vault rather than a project .env file.
  3. Resolve the destination to a dedicated per-user configuration directory rather than relying on the current working directory.
  4. On POSIX systems, securely create a new credential file with mode 0600 and verify ownership and permissions before reading or updating it.
  5. Reject symbolic links and non-regular files. Use safe file-opening primitives such as os.open() with O_NOFOLLOW, where supported.
  6. Write updates atomically through a securely created temporary file in the same private directory, apply restrictive permissions, and then replace the destination.
  7. Add .env to .gitignore and ensure packaging, logging, backup, and diagnostic processes exclude credential files.
  8. Avoid placing the key in exception messages or logs, and document a credential rotation procedure for suspected disclosure.
  9. Validate the final storage permissions and fail closed if a private destination cannot be guaranteed.
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
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (28)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The documented purpose is movie/TV search and link validation, but the described behavior focuses on collecting and persisting an API key, includes unrelated references to school-search functionality, and does not substantiate the claimed media features. This mismatch undermines informed consent and can mislead users into providing secrets to a skill whose real behavior is unclear.

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

The code forcefully reads XBY_APIKEY from the local .env file during initialization rather than relying on normal settings resolution. This broadens secret access behavior and can ingest credentials from disk unexpectedly, which is especially concerning given the skill's mismatched identity and unjustified secret-handling logic.

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

Directly opening and parsing .env to extract a credential is unnecessary and increases the code's active credential-handling surface. This can lead to unintended access to locally stored secrets and makes the component harder to audit and reason about securely.

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

The configuration module includes API-key persistence and global credential mutation behavior that is not justified by a movie/TV search tool description. This mismatch increases the likelihood of hidden or unnecessary secret-handling functionality, which can expose user credentials or enable unauthorized reuse of the API key in a broader, possibly unrelated service context.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill can write a provided API key directly into a local .env file, creating persistent secret storage on disk without clear necessity for a search tool. Persistent local storage raises the risk of credential leakage through source control mistakes, local compromise, backup exposure, or unintended reuse by other processes.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
97% confidence
Finding

The function is explicitly designed to save an API key into a .env file, creating durable plaintext secret storage on disk. In the context of a movie search skill, this is more dangerous because credential persistence is not clearly necessary for the advertised capability and may surprise users or administrators.

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

The skill exposes capabilities implying environment access, file read/write, and network use, but the manifest does not declare any tool scope or permission boundaries. This creates an over-privileged and opaque execution model where the agent may handle secrets and persist data without clear user-facing constraints.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill instructs the agent to ask the user for an API key and then save it via configuration, but it does not clearly warn the user that the secret will be persisted locally, potentially in a .env file. This is dangerous because users may disclose sensitive credentials without understanding retention, exposure, or later reuse risks.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

L037 说明应调用 scripts.tools 中的函数,但示例却是 scripts.tools.search_schools(...),这与全文声明的电影/电视剧搜索与视频链接验证功能明显矛盾。该文档会误导使用者或代理按错误意图调用工具,属于注释/文档与实际技能意图的主动性冲突。

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This code accesses a credential via get_api_key() and sends it in the XBY-APIKEY header during a network request. Although the code logs success and error metadata, there is no confirmation prompt, user-facing warning, or explanatory comment/docstring disclosing that a secret is being used and transmitted to an upstream service.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The docstring and environment namespace identify a different skill domain than the manifest, suggesting code reuse or repurposing without adequate review. In security terms, this undermines trust boundaries because users may grant secrets or permissions to a tool whose internal behavior appears intended for another service.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
82% confidence
Finding

The human-facing class docstring is written only in Chinese, and the file contains user-visible Chinese status/error text, suggesting a fixed language experience. Under the policy, forcing a specific language without user opt-in can be a natural-language policy violation unless the locale constraint is explicitly documented and justified.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The code persists the API key to .env silently, with no user-facing disclosure that credentials will be stored on disk. Users may reasonably expect a transient setting operation, so undisclosed persistence can cause accidental long-term exposure of sensitive credentials.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The printed error message is user-facing natural language and is fixed to Chinese. The policy requires either user choice/opt-in for language or clear justification for a locale-specific constraint; neither is present in this file.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This code invokes external API operations via call_api for movie search and URL validation, which transmit user-provided titles and URLs over the network. The file contains no confirmation prompt, logging, print statement, or user-facing warning comment/docstring disclosing that external requests are made.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

L094 将项目结构标注为 xiaobenyang_gaokao_skill/,而本文件其余部分明确说明这是“电影搜索工具”。这种文档内容表明该技能说明混入了其他项目的描述,和当前代码/技能意图不一致,可能导致维护或调用时理解偏差。

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The dependency uses a lower-bound constraint only, which allows future versions to be installed without review and prevents reproducible builds. This can introduce breaking changes or vulnerable releases transitively, especially for a network-facing package like requests.

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

The manifest does not pin requests, and the package has multiple known advisories across versions, so the security posture of actual installations cannot be verified from this file alone. In a movie/TV search tool that likely performs outbound HTTP requests, an affected requests release could matter more because network input is central to the skill's function.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

Using pydantic>=2.7.0 leaves the installed version unconstrained above the minimum, so builds are not reproducible and may silently pick up vulnerable or incompatible releases. Because pydantic processes untrusted input in many applications, version drift can have security consequences.

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

Because pydantic is not pinned, it is impossible to determine whether deployments are exposed to one of the package's known vulnerable versions. Since pydantic commonly validates untrusted inputs, unresolved version ambiguity is a real supply-chain and application-hardening weakness.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The pydantic-settings package is specified with only a minimum version, which means dependency resolution may install any later release. That weakens supply-chain control and makes it impossible to know from the manifest whether a deployment is using a safe version.

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

The requirements file does not specify an exact pydantic-settings version, so any deployment may resolve to a vulnerable release without visibility in source control. This is a genuine but low-severity dependency-governance issue rather than proof of an active exploitable flaw in the skill itself.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

python-dotenv is unpinned, so environments may resolve to different versions over time, including versions with security defects or incompatible behavior. This is especially relevant for configuration-loading libraries that may touch sensitive files and secrets.

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

Static analysis

No suspicious patterns detected.