Back to skill

Security audit

驾驶证识别OCR

Security checks for vulnerabilities and agentic risk

Overview

This driver-license OCR skill is broadly purpose-aligned, but it needs review because it persists an API key in plaintext and sends sensitive ID images/data to a configurable external endpoint without enough user-facing disclosure.

Install only if you are comfortable sending driver-license images or base64 data to the XiaoBenYang OCR API and storing the XiaoBenYang API key in a local plaintext .env file. Prefer using a dedicated low-privilege API key, verify the endpoint configuration before use, keep .env out of version control and backups, and avoid using this skill for real identity documents unless you have appropriate consent and data-handling assurances.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/config.py:14
Finding
Plaintext API Key Persistence and Configurable Credential Destination<![CDATA[ ## Vulnerability Details **File Location**: `scripts/config.py:14-62`, `scripts/call_api.py:49-72` **Vulnerability Type**: Plaintext secret storage and unsafe configurable outbound endpoint **Risk Level**: Medium ### Vulnerable Code ```python class Settings(BaseSettings): """小笨羊高考Skill配置""" model_config = SettingsConfigDict( env_prefix="XBY_GAOKAO_", env_file=".env", env_file_encoding="utf-8", extra="ignore", ) # API配置 base_url: str = "https://mcp.xiaobenyang.com" mcp_id: str = "1820705335657482" api_key: str = "" # 超时和重试配置 timeout_seconds: float = 30.0 max_retries: int = 2 # 数据配置 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") for line in content.splitlines(): 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 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( ...[truncated 3143 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Store the API key in an operating-system credential manager or managed secrets service rather than a project-local plaintext file. 2. If `.env` persistence must remain supported: - Create the file atomically. - Set its mode explicitly to `0600`. - Verify ownership and permissions before reading or updating it. - Refuse to use symlinked or non-regular `.env` files. - Ensure `.env` is excluded from version control, packaging, logs, and backups. 3. Remove production support for overriding `base_url` through an untrusted environment. 4. If endpoint configuration is required, validate the parsed URL: - Require HTTPS. - Permit only an explicit hostname allowlist such as `mcp.xiaobenyang.com`. - Reject embedded credentials, unexpected ports, IP-literal destinations, and malformed URLs. 5. Disable redirects or validate every redirect destination before forwarding authentication headers or request bodies. 6. Warn users clearly that driving-license data is transmitted to a third-party OCR service and obtain appropriate consent before submission. 7. Rotate any API key that may have been stored with permissive file permissions or used while the endpoint configuration was untrusted. ]]>

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding
Unbounded Third-Party Dependency Versions<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:1-4` **Vulnerability Type**: Non-reproducible dependency resolution and supply-chain exposure **Risk Level**: Low ### Vulnerable Code ```text requests>=2.31.0 pydantic>=2.7.0 pydantic-settings>=2.2.0 python-dotenv>=1.0.1 ``` ### Technical Analysis Every dependency uses only a minimum-version constraint. A fresh installation may therefore resolve to any later release accepted by the package resolver, including major versions with incompatible behavior or future releases that have not been reviewed by the project. This does not prove that any currently listed package is malicious. The security weakness is the absence of a reproducible, reviewed dependency set. Because imported dependencies participate directly in HTTP communication, environment parsing, and settings construction, an unintended or compromised future release could affect secret handling or outbound requests. The requirements file also lacks package hashes. Package artifacts are consequently not verified against a project-approved cryptographic digest during installation. ### Attack Path 1. The project is installed or rebuilt without a reviewed lock file or constraints file. 2. The resolver selects a newer dependency release allowed by the open-ended `>=` constraint. 3. The selected version contains a malicious change, compromised distribution artifact, exploitable defect, or security-relevant behavioral incompatibility. 4. Package code executes during installation or import, or changes HTTP/configuration behavior at runtime. 5. Depending on the affected dependency, the API key, OCR request data, process environment, or application availability may be compromised. This path depends on a compromised, vulnerable, or unexpectedly incompatible dependency release; no such release was established by the reviewed source alone. ### Impact Assessment The potential scope is the privilege level of the process installing or runn ...[truncated 437 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin dependencies to exact, reviewed versions in a lock file or compiled requirements file. 2. Generate and enforce cryptographic hashes for all distributions, for example by installing with `pip --require-hashes`. 3. Separate direct requirements from fully resolved transitive dependencies using a controlled tool such as `pip-tools`, Poetry, or an equivalent lock-file workflow. 4. Review dependency updates through pull requests and automated tests rather than accepting future releases automatically. 5. Run vulnerability and provenance scanning in CI for both direct and transitive dependencies. 6. Prefer trusted package indexes configured explicitly, and prevent fallback to unapproved indexes to reduce dependency-confusion risk. 7. Rebuild lock files on a controlled schedule so security updates can be adopted without restoring open-ended dependency resolution. ]]>
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 (30)

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
95% confidence
Finding
The skill claims to perform OCR, but also instructs the agent to read and persist API keys in .env/config state. Persisting credentials and modifying local configuration materially exceeds the declared purpose and creates risk of credential leakage, unintended reuse, or unauthorized config tampering, especially in a skill handling sensitive government ID data.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill claims to perform OCR, but also instructs the agent to read and persist API keys in .env/config state. Persisting credentials and modifying local configuration materially exceeds the declared purpose and creates risk of credential leakage, unintended reuse, or unauthorized config tampering, especially in a skill handling sensitive government ID data.

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
75% confidence
Finding
The custom post-init logic explicitly opens and parses .env to extract XBY_APIKEY, bypassing normal settings handling and increasing secret exposure in code paths that do not need it. In a skill whose stated purpose is OCR, this secret-harvesting behavior is harder to justify and more suspicious.

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
75% confidence
Finding
This line participates in direct filesystem access to a .env file for credential retrieval, contributing to unnecessary credential handling in the skill. Directly reading local secret files can expose credentials through logs, debugging, path confusion, or reuse in unintended contexts.

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
93% confidence
Finding
This function is dedicated to saving an API key into a local .env file, creating durable plaintext credential storage under application control. That enables secret leakage through source-control mistakes, artifact collection, multi-user hosts, or later compromise of the working directory.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill declares no explicit tool/permission scope even though its documented behavior includes environment access, local file writes, and network/API use. Without least-privilege constraints, a runtime may grant broader capabilities than users expect, increasing the blast radius if the skill is abused or misrouted.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
This skill processes highly sensitive personal data from driver's licenses, including identity numbers, address, birth date, and license details, and the documentation indicates external API transmission without any privacy warning, consent flow, retention notice, or data-handling limitations. In this context, the absence of disclosure is especially dangerous because users may unknowingly send regulated identity data to a third-party service.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
该技能声明用途是驾驶证 OCR,但文档在调用示例中写成 `scripts.tools.search_schools(...)`,并在项目结构中标注目录名为 `xiaobenyang_gaokao_skill/`,明显对应高考/学校查询场景而非驾驶证识别。这不是单纯遗漏,而是文档内容主动指向了另一类功能,会误导代理如何调用代码。

Missing User Warnings

Medium
Confidence
93% confidence
Finding
This code performs a network POST request and sends both caller-provided parameters and an authentication key upstream. While it has internal logging for success and errors, there is no user-facing warning, confirmation, or explanatory comment/docstring disclosing that data will be transmitted to an external service.

Description-Behavior Mismatch

Medium
Confidence
88% confidence
Finding
This code manages and persists an external API key even though the stated skill purpose is only driving-license OCR. That mismatch expands the skill's capabilities into credential handling and local secret persistence, which increases the attack surface and can enable misuse or unauthorized reuse of the credential.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The function writes API credentials into a local .env file, creating persistent plaintext secret storage on disk. If the workspace is shared, committed, backed up, or readable by other processes, the credential can be exposed and later abused.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The code persists an API key without any user-facing warning, confirmation, or transparency about long-term storage. Silent secret persistence is dangerous because users may provide a temporary credential without realizing it will be written to disk and remain accessible.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
This function sends driver license imagery or extracted identity-document content to an external API, but the file shows no visible consent prompt, disclosure, data-minimization, or handling constraints for highly sensitive personal information. Because driver licenses contain government ID numbers and other PII, silent transmission increases privacy, compliance, and misuse risk if users are unaware or the downstream service is not adequately governed.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
This variant accepts a base64-encoded image of a driver's license and forwards it to an external API, again with no visible warning or consent mechanism in the code. Base64 transport does not reduce sensitivity; it still contains the full identity document image, creating substantial privacy and regulatory exposure if collected or transmitted without clear notice and safeguards.

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, so builds may resolve to different versions over time and can unintentionally pull in vulnerable or incompatible releases. For a skill that processes driver license OCR data, dependency drift increases supply-chain risk and can expose sensitive personal information if a compromised or vulnerable package version is installed.

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
requests has known security advisories, and because the manifest does not pin a version, it is impossible to verify that deployed instances avoid affected releases. In a network-facing OCR integration, an affected HTTP client could leak credentials or mishandle transport security, which matters more because the skill likely processes sensitive identity data.

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
Using pydantic with only a minimum version allows non-reproducible installations and may introduce a vulnerable release without code changes. This is especially relevant in an OCR skill handling identity document fields, where a compromised dependency could affect confidentiality or service reliability.

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
pydantic has known advisories, and the absence of exact version pinning means the deployed version cannot be verified as safe. If a vulnerable release is installed, parsing or validation bugs could be abused for denial of service or incorrect handling of OCR-extracted personal data.

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
An unpinned pydantic-settings dependency creates supply-chain uncertainty because future installs may fetch different versions with different security properties. In a settings-handling package, that can be risky if later vulnerable releases affect secret loading or configuration parsing.

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
85% confidence
Finding
pydantic-settings has a cited advisory, and without version pinning there is no assurance that an installed release is unaffected. Since this package may load secrets or configuration from files, a vulnerable version could increase the risk of unsafe secret resolution or local file exposure.

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 specified without an exact version, which can cause unpredictable installs and make it hard to prove whether deployed environments are safe. Because dotenv libraries often interact with local configuration and secrets, version drift can increase the chance of secret exposure or unsafe file handling if a bad release is selected.

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
python-dotenv has known advisories related to filesystem handling, and the unpinned requirement prevents verification that the deployed version avoids them. In an application that may run with access to local configuration and credentials, vulnerable dotenv behavior could contribute to secret exposure or unsafe file writes.

Static analysis

No suspicious patterns detected.