Back to skill

Security audit

验证码识别OCR

Security checks for vulnerabilities and agentic risk

Overview

This CAPTCHA OCR skill mostly does what it says, but it persistently stores an API key in plaintext and can send that key plus submitted images to a configurable remote endpoint.

Install only if you are comfortable giving this skill a XiaoBenYang API key and sending CAPTCHA images or image URLs to its remote service. Treat the saved .env key as a local secret, avoid running it in shared or untrusted workspaces, and prefer a disposable/limited API key until the package documents storage, deletion, endpoint allowlisting, and data handling more clearly.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/call_api.py:56
Finding
API Credential and OCR Data Can Be Sent to a Configurable Untrusted Endpoint## Vulnerability Details **File Location**: `scripts/config.py:11-21`, `scripts/call_api.py:56-78` **Vulnerability Type**: Unvalidated configurable API destination **Risk Level**: High ### Vulnerable Code `scripts/config.py:11-21`: ```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/call_api.py:56-78`: ```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", } # 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 The Pydantic settings configuration uses the `XBY_GAOKAO_` environment prefix. Consequently, the `base_url` field can be overridden through `XBY_GAOKAO_BASE_URL` or a corresponding settings source. The client does not validate the resulting URL against an approved origin and does not require the configured destination to use HTTPS. It constructs the API URL directly from this configurable value and sends the API credential in the `XBY-APIKEY` header. The request body also contains the user-provided image URL or Base64-encoded image. An attacker who can influence the process environment or relevant configuration can redirect requests to an attacker-controlled server. This is a credential and application-data exfiltration issue rather than server-side reque ...[truncated 1373 chars]
Remediation
## Remediation Suggestions 1. Remove runtime configurability for the production API origin where it is not required. 2. Validate `settings.base_url` before every request using a parsed URL rather than string-prefix checks. 3. Require the `https` scheme and reject URLs containing user information, unexpected ports, fragments, or unapproved hostnames. 4. Maintain an explicit allowlist containing the exact expected origin, such as `https://mcp.xiaobenyang.com`. 5. Resolve and validate redirect destinations, or disable automatic redirects for authenticated requests. 6. Never forward `XBY-APIKEY` to a destination whose scheme, hostname, and port do not exactly match the approved API origin. 7. If endpoint overrides are needed for development, gate them behind an explicit development mode and use separate non-production credentials. 8. Add tests confirming that HTTP URLs, lookalike domains, embedded credentials, unexpected ports, and attacker-controlled environment overrides are rejected.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/config.py:45
Finding
API Key Is Persisted in a Plaintext .env File Without Explicit Access Restrictions## Vulnerability Details **File Location**: `scripts/config.py:45-63` **Vulnerability Type**: Insecure plaintext credential storage **Risk Level**: Medium ### Vulnerable Code ```python def save_api_key_to_env(api_key: str) -> bool: """Persist the 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 ``` ### Technical Analysis The Skill automatically stores the API credential in a plaintext `.env` file in the current working directory. `Path.write_text()` does not explicitly enforce owner-only permissions. For a newly created file, effective permissions depend on the process umask; for an existing file, insecure permissions may remain unchanged. The implementation also does not use an operating-system credential store, encrypted secret storage, or session-only handling. Because `.env` is a conventional project file, it may also be included accidentally in source-control commits, archives, build contexts, diagnostics, or backups. The Skill documentation explicitly directs the agent to obtain the key from the user and persist it through `set_api_key()`, making storage part of the normal workflow rather than an exceptional operation. ### Attack Path 1. A user supplies a valid API key to the Skill. 2. `set_api_key()` invokes `save_api_key_to_env()`. 3. The key is written in plaintext as `X ...[truncated 858 chars]
Remediation
## Remediation Suggestions 1. Prefer session-only credential handling and avoid persistent storage unless the user explicitly requests it. 2. Store persistent credentials in an operating-system secret manager or an equivalent managed credential service. 3. If `.env` persistence is unavoidable, create the file atomically with owner-only permissions such as `0600`. 4. Verify and correct the permissions of existing `.env` files before writing credentials. 5. Store the file in a controlled application configuration directory rather than relying on the current working directory. 6. Add `.env` to `.gitignore`, packaging exclusion lists, backup exclusions where appropriate, and container build exclusions. 7. Avoid printing or logging the API key, including in error paths. 8. Provide a supported method to delete the persisted credential and document key rotation procedures. 9. Request explicit informed consent before retaining the key across sessions.
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 (33)

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
98% confidence
Finding
The skill description says CAPTCHA OCR, but the project structure and instructions reference .env management, API credential storage, and gaokao-related configuration, which is a substantial functionality mismatch. Such inconsistencies are a strong trust and security problem because they suggest the skill may be repurposed code with hidden or poorly understood behaviors, including secret persistence and unrelated service access.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill description says CAPTCHA OCR, but the project structure and instructions reference .env management, API credential storage, and gaokao-related configuration, which is a substantial functionality mismatch. Such inconsistencies are a strong trust and security problem because they suggest the skill may be repurposed code with hidden or poorly understood behaviors, including secret persistence and unrelated service access.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The file implements configuration and credential management for a Gaokao-related remote service, which is materially inconsistent with the declared purpose of a captcha OCR skill. This kind of scope mismatch is dangerous because it introduces undocumented network/service access and secret handling capabilities that users would not reasonably expect from the skill, increasing the risk of hidden data access or repurposing.

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
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
93% confidence
Finding
This code explicitly opens and reads the local .env file to extract a specific API key outside the normal settings framework. That direct secret access is more concerning because it bypasses transparent configuration patterns, targets a non-namespaced variable, and is inconsistent with the declared OCR skill purpose.

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
90% confidence
Finding
Reading a sensitive API key directly from the process environment into application state is credential access behavior. In an OCR skill context, this is more dangerous because it is unexpected, uses a generic variable name, and could consume secrets that belong to another tool or service without clear user awareness.

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 is dedicated to saving an API key into a plaintext .env file, creating persistent local secret storage. Plaintext persistence materially increases the blast radius of credential compromise and is especially suspicious in a skill whose advertised purpose is simply recognizing captcha text.

Lp3

Medium
Category
MCP Least Privilege
Confidence
85% confidence
Finding
The skill declares capabilities that imply environment access, file reads/writes, and network use, but it does not define any explicit tool scope or permission boundary. In this context, the skill also requests an API key and persists it locally, so the lack of scoped permissions increases the chance of overbroad access and accidental secret exposure.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill instructs the agent to ask the user for an API key and then persist it via configuration, but it does not warn that the secret will be stored locally or explain retention and access implications. This creates a real secret-handling risk because users may disclose credentials without informed consent, and persisted secrets can later be exposed through logs, files, or other tools.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The workflow example instructs calling an unrelated school-search function instead of the OCR functions declared by the skill. This kind of stale or mismatched routing guidance can cause the agent to invoke unintended tools or pass user data into the wrong backend, which is especially risky when network calls and stored API keys are involved.

Missing User Warnings

Medium
Confidence
81% confidence
Finding
The function retrieves an API key and includes it in the outbound request headers, which is a sensitive-credential operation covered by the warning requirement. The file does not provide any user-facing warning or explanatory comment/docstring that the skill uses stored credentials to authenticate outbound requests.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
This code sends `params` to an external HTTP endpoint via `requests.Session.post`, which may transmit user or system data off-box. While there is internal logging for success and errors, there is no confirmation prompt, user-facing notice, or explanatory comment/docstring warning that request data will be sent to an upstream service.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The class docstring explicitly identifies this as configuration for a Gaokao skill, contradicting the manifest's captcha OCR description. Such contradiction is a strong indicator of repackaged or misleading code, which undermines trust and suggests hidden or undeclared behavior beyond the user's expected scope.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
The code reads and persists API credentials in a local .env file even though such credential management is not justified by the stated captcha OCR function. Persisting secrets locally expands exposure through accidental check-in, local disclosure, and unauthorized reuse, especially when users are not clearly informed that the skill will store credentials.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The function writes a supplied API key directly into .env and process environment state without any user-facing warning, consent flow, or security notice. Silent persistence of secrets is risky because users may not realize credentials are being stored on disk, where they can later be exposed through backups, logs, repository commits, or local compromise.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
This function sends a user-supplied image URL to an external API service via call_api without any disclosure, consent flow, or indication of where the image will be processed. Because CAPTCHA images may be sensitive authentication artifacts and the skill is explicitly designed to solve them, this creates both privacy risk and misuse risk by silently transmitting user data off-platform.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
This function transmits raw base64-encoded image content to an external API, which can include sensitive image data and authentication challenges, without any visible warning or consent mechanism in the code. The risk is heightened because base64 input commonly contains the full image payload, so users may unknowingly exfiltrate data directly to a remote service.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
The skill name and description are presented in Chinese, and the file does not indicate that users may interact in other languages or that the locale restriction is intentional and justified. Under the stated policy, forcing a specific language without user opt-in can be a natural-language policy issue.

Missing User Warnings

Low
Confidence
89% confidence
Finding
The skill directs the agent to display the raw API response directly to the user without any filtering or sensitivity review. Even for an OCR task, raw responses can contain metadata, tokens, internal error traces, or other sensitive fields that should not be exposed verbatim.

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
The dependency specifier `requests>=2.31.0` is unpinned, so builds may resolve to different versions over time, reducing reproducibility and making it harder to ensure known-vulnerable releases are excluded. In a security-sensitive skill that may process user-supplied images and make outbound requests, this increases supply-chain and patch-verification risk even though the file alone does not prove exploitation.

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
`requests` has multiple known advisories, and because the manifest does not pin a version, there is no way to verify from this file whether a safe or vulnerable release will be installed. Given this OCR skill may reasonably perform network operations, an affected `requests` version could expose credential leakage, TLS, or request-handling weaknesses depending on runtime usage.

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
`pydantic>=2.7.0` allows installation of any newer major/minor/patch release, which can introduce unreviewed code changes or pull in versions later found vulnerable. This is primarily a dependency hygiene and supply-chain risk rather than an immediately exploitable flaw in isolation.

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
`pydantic` has known advisories, but the open-ended version range prevents determining whether deployed environments will avoid them. In a skill handling user-controlled input, parser/validation library issues can matter, even if this requirements file alone does not show direct exploitability.

Static analysis

No suspicious patterns detected.