Back to skill

Security audit

行驶证识别OCR

Security checks for vulnerabilities and agentic risk

Overview

The vehicle-license OCR skill has a coherent purpose, but it stores an API key in plaintext and can send sensitive document data to a configurable external API, so it belongs in Review before installation.

Install only if you are comfortable sending vehicle-license images or base64 contents to the XiaoBenYang API and storing the service API key in a local .env file. Prefer a runtime secret store, pin dependencies, restrict or remove base_url overrides, and add a clear privacy notice before using it with real personal or vehicle-registration documents.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/config.py:10
Finding
Environment-Controlled API Endpoint Can Expose Credentials and Sensitive Documents<![CDATA[ ## Vulnerability Details **File Location**: `scripts/config.py:10-15`; data transmission occurs at `scripts/call_api.py:50-70` **Vulnerability Type**: Unvalidated configurable network destination **Risk Level**: Medium ### Complete Code Snippet ```python # scripts/config.py:10-15 model_config = SettingsConfigDict( env_prefix="XBY_GAOKAO_", env_file=".env", env_file_encoding="utf-8", extra="ignore", ) base_url: str = "https://mcp.xiaobenyang.com" ``` ```python # scripts/call_api.py:50-70 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 `SettingsConfigDict` uses the `XBY_GAOKAO_` environment-variable prefix. Consequently, `XBY_GAOKAO_BASE_URL` can override the default `base_url`. The resulting value is used directly to construct the request destination without validating the scheme, hostname, port, or final origin. Every request to the configured destination contains the `XBY-APIKEY` credential. The body can also contain either a vehicle-license image URL or the complete Base64-encoded image. Vehicle licenses may disclose names, addresses, license-plate numbers, vehicle identification numbers, and engine numbers. Exploitation requires the attacker to influence the Skill process environment or its configuration. This is not a remote unauthenticated vulnerability by itself, but it becomes a credential and personal-data disclosure issue in environments where deployment variables, launch configuration, or `.env` settings are ...[truncated 968 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin the production API origin in code if endpoint customization is not required. - If customization is required, parse the URL and enforce an exact allowlist of approved HTTPS origins. - Reject non-HTTPS schemes, embedded credentials, unexpected ports, fragments, and malformed URLs. - Disable cross-origin redirects or verify the final redirect destination before forwarding credentials. - Do not attach the API-key header after a redirect to a different origin. - Separate development endpoint configuration from production configuration and require an explicit trusted deployment mode for overrides. - Add tests proving that HTTP URLs, attacker-controlled domains, user-info components, and cross-origin redirects are rejected. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/config.py:39
Finding
API Key Is Persisted in a Plaintext File Without Permission Hardening<![CDATA[ ## Vulnerability Details **File Location**: `scripts/config.py:39-59` **Vulnerability Type**: Insecure storage of sensitive credentials **Risk Level**: Medium ### Complete Code Snippet ```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 directly into `.env` as plaintext. The implementation does not explicitly create the file with restrictive permissions, verify its ownership, reject symbolic links, or use an operating-system credential store. The effective permissions depend on the process umask and any pre-existing file permissions. A pre-existing broadly readable `.env` remains broadly readable after `write_text()`. Storing the secret inside the project working directory also increases the possibility of accidental inclusion in source-control commits, archives, support bundles, or backups. Exploitation requires local filesystem access, access to an accidentally published project copy, or another mechanism that exposes the working directory. There is no evidence that the code intentionally transmits the saved key elsewhere. ### Attack Path 1. A user supplies an API key and `set_api_key()` invokes `save_api_key_to_env()`. 2. The function stores the complete ...[truncated 727 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Prefer an operating-system secret store, deployment secret manager, or session-only environment variable instead of project-directory persistence. - If file persistence is unavoidable, create the file atomically with mode `0600` and verify that it is owned by the expected account. - Refuse to write through symbolic links and avoid predictable shared-directory paths. - Check and correct permissions on pre-existing `.env` files before storing the key. - Add `.env` to `.gitignore` and relevant packaging, backup, and diagnostic-bundle exclusion lists. - Avoid printing, logging, or returning the API key in error messages. - Document credential rotation and immediately rotate any key suspected of having been committed or otherwise disclosed. ]]>

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding
Unbounded Dependency Versions Make Builds Non-Reproducible<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:1-4` **Vulnerability Type**: Unpinned third-party dependencies **Risk Level**: Low ### Complete Code Snippet ```text requests>=2.31.0 pydantic>=2.7.0 pydantic-settings>=2.2.0 python-dotenv>=1.0.1 ``` ### Technical Analysis All dependencies use open-ended minimum-version constraints. A future installation may therefore resolve to versions that were not present during the audit and have not been reviewed for compatibility or security. This prevents reproducible builds and increases exposure to compromised releases, newly introduced vulnerabilities, and unexpected behavior changes. The listed package names correspond to known packages, and the reviewed files do not establish dependency confusion, typosquatting, or a currently malicious release. The finding concerns unsafe dependency-management practice rather than evidence that the current dependencies are malicious. ### Attack Path 1. The project is installed at a later time without a reviewed lock file or constraints file. 2. The package resolver selects newer releases satisfying the open-ended `>=` constraints. 3. A selected release contains a compromised distribution, exploitable regression, or incompatible behavior. 4. Package installation or runtime import executes or exposes the affected dependency behavior in the Skill environment. The practical exploitability depends on the package index, selected versions, installation controls, and whether a malicious or vulnerable compatible release is available. ### Impact Assessment A compromised dependency could execute with the privileges of the account installing or running the Skill. A non-malicious but incompatible update could also cause availability or integrity failures. No existing dependency compromise was identified from the supplied project files. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Generate and commit a reviewed lock or constraints file containing exact dependency versions. - Use cryptographic package hashes, such as pip's `--require-hashes`, for deployment installations. - Resolve dependencies only from explicitly trusted package indexes. - Perform automated vulnerability and license scanning during continuous integration. - Review dependency changes before updating the lock file. - Rebuild the lock file regularly so security updates are adopted through a controlled process rather than through unrestricted resolution at deployment time. ]]>
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)

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
96% confidence
Finding
The skill is presented as a vehicle-license OCR tool, but it also manages and persists API keys via .env and accesses environment/configuration state, behavior not disclosed in the user-facing purpose statement. Because the handled document contains highly sensitive personal and vehicle-registration data, hidden credential-management and storage behavior materially increases security and privacy risk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill is presented as a vehicle-license OCR tool, but it also manages and persists API keys via .env and accesses environment/configuration state, behavior not disclosed in the user-facing purpose statement. Because the handled document contains highly sensitive personal and vehicle-registration data, hidden credential-management and storage behavior materially increases security and privacy risk.

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
82% confidence
Finding
The code forcefully reads .env content and manually extracts XBY_APIKEY, bypassing normal configuration boundaries and increasing secret exposure within the application. In an OCR-only skill, custom secret parsing is unnecessary and makes credential access behavior more suspicious and harder to audit.

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
82% confidence
Finding
Checking for and opening a local .env file to read credentials is a form of direct secret access that broadens the application's handling of sensitive data. This is especially questionable in a document OCR skill where secret file inspection is not part of the core function and can facilitate later misuse or exfiltration.

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
95% confidence
Finding
This function explicitly persists an API key into a .env file, creating durable credential storage on disk that may be readable by other processes, accidentally committed, or harvested later. Because the skill's stated purpose is OCR, this credential-storage capability is not well-justified and materially increases the danger of secret compromise.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill exposes capabilities for environment access, file read/write, and network use, but does not declare any explicit permission or allowed-tool scope. This weakens least-privilege controls and makes it harder for reviewers and runtime policy to constrain sensitive operations such as API-key storage and outbound transmission.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The skill instructs sending vehicle registration images or base64-encoded document contents to an external OCR API, but it does not provide an explicit privacy notice, consent flow, retention policy, or warning about third-party data sharing. Because vehicle licenses contain highly sensitive personal information, undisclosed external transmission creates significant privacy, compliance, and misuse risk.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
References to an unrelated 'gaokao' project/function example inside a vehicle-license OCR skill indicate copy-paste inconsistency and poor provenance control. Such inconsistency raises the chance of misrouted tool calls, reviewer confusion, and accidental invocation of unintended functionality, which is especially risky in a skill that handles sensitive documents and credentials.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
This code performs an HTTP POST to an external endpoint and sends both caller-supplied parameters and an API key in headers. While it logs success and errors internally, there is no confirmation prompt or user-facing warning in the file explaining that user/system data may be transmitted off-box.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The OCR skill includes logic to persist and manage an API key in a local .env file, which is broader than what is necessary for simple document recognition and expands the credential-handling attack surface. Storing secrets on disk can expose them to other local users, accidental source control commits, backups, or unrelated components that can read the workspace.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The function writes API credentials directly to a local .env file without any access-control hardening or purpose limitation tied to OCR processing. In this skill context, local credential file write capability is unnecessary and increases the chance of secret leakage through filesystem exposure, repository inclusion, or later exfiltration by other code.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The code silently persists an API key to .env with no user-facing warning or confirmation, creating a risk that operators do not realize credentials are being stored on disk. Hidden persistence increases the likelihood of accidental disclosure via local inspection, backups, logs, or source control.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
This function sends vehicle license image content or a URL to an external API for OCR, which involves highly sensitive personal and vehicle-identifying data. The file provides no visible consent flow, privacy notice, data-handling constraints, or safeguards around what endpoints may receive the data, so users may unknowingly transmit regulated personal information off-platform.

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, which allows future installs to resolve to different versions over time. This weakens reproducibility and can unintentionally pull in vulnerable or breaking releases of requests, especially relevant because this OCR skill likely handles sensitive vehicle document data and may make outbound API calls.

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
90% confidence
Finding
The manifest does not pin requests, and the package has multiple known advisories across versions, so the actual installed version may be affected without visibility. In an OCR integration, requests is likely used for network communication, making credential leakage, TLS handling flaws, or other client-side issues more consequential if a vulnerable release is 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
95% confidence
Finding
Using pydantic with only a minimum version means builds are not deterministic and may consume later versions with newly introduced vulnerabilities or incompatible behavior. Since this package is often involved in parsing untrusted input and configuration, version drift increases security and reliability risk.

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
87% confidence
Finding
Because pydantic is not pinned, it is impossible to verify from this file whether deployment uses a version affected by known advisories such as denial-of-service issues. If the skill parses attacker-controlled OCR outputs, request bodies, or configuration, a vulnerable parser version could increase exposure to malformed-input attacks.

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 unpinned pydantic-settings requirement permits uncontrolled version selection during installation. That can expose deployments to supply-chain instability or known package flaws if a later resolved release is vulnerable.

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
The dependency on pydantic-settings is unverifiable because no exact version is fixed, and at least one advisory exists for the package. Given that settings libraries often read secrets and filesystem paths, an affected version could have security implications if the application uses nested secrets or local secret mounts.

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
python-dotenv is also unpinned, so different environments may install different versions, including releases later found to contain security defects. For software that may process sensitive OCR-related credentials or API settings from .env files, this increases operational and security uncertainty.

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
86% confidence
Finding
python-dotenv has known advisories, but without an exact version the resolved package may still be vulnerable. Because dotenv tooling can read or modify environment files containing API keys and service credentials, flaws such as symlink-following could matter in certain deployment or local tooling scenarios.

Intent-Code Divergence

Low
Confidence
98% confidence
Finding
The class docstring says '小笨羊高考Skill配置', which refers to a gaokao/exam-related skill rather than the manifest's vehicle license OCR skill. This active documentation mismatch suggests the file was repurposed without updating intent documentation, creating ambiguity about the skill's true purpose.

Static analysis

No suspicious patterns detected.