Back to skill

Security audit

发票识别(invoice-discern) - 慧穗云

Security checks for vulnerabilities and agentic risk

Overview

This invoice OCR skill does what it claims, but it can send sensitive invoices and authentication material to any API host configured in the environment.

Review before installing. Use this only with invoices you are allowed to submit to Huisuiyun, set HSY_API_URL only to the trusted HTTPS service, protect HSY_AK and HSY_SK, and avoid running it in environments where another party can control environment variables.

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
invoice-discern.py:14
Finding

Unrestricted API Endpoint Allows Disclosure of Credentials and Invoice Data

Content
View full analysis

Vulnerability Details

File Location: invoice-discern.py, lines 14–25 and 33–62
Vulnerability Type: Unvalidated destination URL for sensitive network requests
Risk Level: High

Vulnerable Code

python
def get_token(api_url, ak, sk, type_value):
    """获取访问令牌"""
    token_url = f"{api_url}/api/v2/agent/common/cdk/getToken"
    secret_string = get_md5(ak + sk)

    payload = {
        "akString": ak,
        "secretString": secret_string,
        "type": int(type_value),
        "forceUpdate": 0
    }

    try:
        response = requests.post(token_url, json=payload)
        result = response.json()
        if result.get("code") == "200":
            return result["data"]
        else:
            return None, result.get("message", "获取Token失败")
    except Exception as e:
        return None, str(e)
python
def discern_invoice(file_path, tax_no=None):
    """识别发票"""
    api_url = os.getenv("HSY_API_URL", "https://huisuiyun.com")
    ak = os.getenv("HSY_AK")
    sk = os.getenv("HSY_SK")
    type_value = os.getenv("HSY_TYPE", "2")

    # ...

    headers = {"X-Access-Token": token}
    if type_value == "1" and tax_no:
        headers["X-Tax-Token"] = tax_no

    discern_url = f"{api_url}/api/v2/agent/cdk/invoice/discern"

    try:
        with open(file_path, 'rb') as f:
            files = {'file': f}
            response = requests.post(discern_url, files=files, headers=headers)
        return response.json()
    except Exception as e:
        return {"error": str(e)}

Technical Analysis

The destination for both authentication and invoice-upload requests is controlled through the HSY_API_URL environment variable. The implementation concatenates API paths onto this value without validating its scheme, hostname, port, user-information component, or final destination.

Consequently, the value may point to an arbitrary HTTP or HTTPS ...[truncated 3298 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin the production API origin. Use a constant such as https://huisuiyun.com rather than accepting an unrestricted environment-provided URL.

    python
    API_ORIGIN = "https://huisuiyun.com"
    
  2. If endpoint configurability is operationally necessary, enforce an explicit allowlist. Parse the URL and require:

    • The https scheme.
    • An exact approved hostname.
    • No username or password component.
    • No fragments.
    • Only an approved port, normally 443.
    python
    from urllib.parse import urlparse
    
    ALLOWED_HOSTS = {"huisuiyun.com"}
    
    def validate_api_url(value):
        parsed = urlparse(value)
        if (
            parsed.scheme != "https"
            or parsed.hostname not in ALLOWED_HOSTS
            or parsed.username is not None
            or parsed.password is not None
            or parsed.port not in (None, 443)
            or parsed.fragment
        ):
            raise ValueError("Unapproved HSY API endpoint")
        return f"https://{parsed.hostname}"
    
  3. Do not silently permit development endpoints in production. If testing against alternate servers is required, place that capability behind an explicit development-only option and use a separate set of non-production credentials.

  4. Set connection and response timeouts on both requests to limit denial-of-service exposure:

    python
    response = requests.post(token_url, json=payload, timeout=(5, 30))
    response.raise_for_status()
    
  5. Validate authentication responses strictly. Confirm the HTTP status, response content type, expected JSON structure, and token type before using the returned value.

  6. Avoid redirecting sensitive requests to unapproved origins. Disable redirects or validate every redirect destination before forwarding credentials or invoice data:

    python
    requests.post(..., allow_redirects=False)
    

...[truncated 555 chars]

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (8)

Tainted flow: 'discern_url' from os.getenv (line 64, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
95% confidence
Finding

The destination URL is derived from the HSY_API_URL environment variable and is used directly in requests.post while sending the invoice file and access token headers. In a hostile or misconfigured environment, this allows exfiltration of sensitive invoice documents and authentication material to an attacker-controlled endpoint, making the issue more serious because this skill’s core purpose handles financial documents.

Content

Scanner excerpt · invoice-discern.py (reported line 69)May include surrounding context.

python
try:
        with open(file_path, 'rb') as f:
            files = {'file': f}
            response = requests.post(discern_url, files=files, headers=headers)
        return response.json()
    except Exception as e:
        return {"error": str(e)}

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill requires environment secrets and makes networked API calls, but it does not declare an explicit tool scope such as permissions or allowed-tools. This weakens governance and user awareness because the agent may access credentials and transmit data externally without a clearly documented capability boundary.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill processes invoice images and extracted invoice fields through a third-party API, but the description does not clearly warn users that potentially sensitive financial and personal data will leave the local environment. This creates a meaningful privacy and compliance risk because users may unknowingly submit confidential invoice contents, tax IDs, names, routes, and other billing data to an external processor.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · invoice-discern.py (reported line 25)May include surrounding context.

python
}

    try:
        response = requests.post(token_url, json=payload)
        result = response.json()
        if result.get("code") == "200":
            return result["data"]

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The code uploads the provided invoice file to a remote API with no in-code confirmation, warning, or transparency to the caller about external transmission. Because invoices commonly contain sensitive business and personal data, undisclosed remote upload creates privacy, compliance, and data-handling risk even if it is part of the intended functionality.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The natural-language instructions and usage guidance are effectively restricted to Chinese, which can amount to a language policy issue when no user opt-in or alternative language is provided. The file does not state that the skill is intentionally limited to Chinese-speaking users or a China-specific compliance context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

User-facing docstrings and error/help messages are written in Chinese only, including setup guidance and usage-related text. This imposes a specific language on users without any option to select another locale or indication that the skill is intended solely for a Chinese-language context.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The skill accesses HSY_AK and HSY_SK from environment variables to authenticate with the external service. The code includes an error message when the variables are missing, but it does not clearly disclose in comments, docs, or runtime output that the skill uses these sensitive credentials for remote authentication.

Content

No source excerpt is available for this finding.