Back to skill

Security audit

ZhenInsure 真机保险 | Insurance Broker

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly behaves like a disclosed insurance chat API proxy, but it can be configured to send the user's API key and sensitive consultation data to an arbitrary base URL.

Install only if you trust the publisher and can control the runtime configuration. Before use, verify that ZHENINSURE_BASE_URL is unset or restricted to an approved ZhenInsure origin, treat the API key as a production secret, and avoid sending real health, financial, or customer data unless you have consent and understand ZhenInsure's data handling terms.

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
actions/proxy.js:52
Finding
Unrestricted Base URL Override Exposes API Credentials and Conversation Data## Vulnerability Details **File Location**: `actions/proxy.js:52-56, 105, 110-116` **Vulnerability Type**: Unvalidated outbound request destination / credential disclosure **Risk Level**: High ### Vulnerable Code ```js const baseUrl = normBase( context?.config?.ZHENINSURE_BASE_URL ?? context?.env?.ZHENINSURE_BASE_URL ?? process.env.ZHENINSURE_BASE_URL ); ``` ```js const url = `${baseUrl}${endpoint}`; let res; try { const ctl = new AbortController(); const timer = setTimeout(() => ctl.abort(), REQUEST_TIMEOUT_MS); res = await fetch(url, { method, headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}`, "User-Agent": `ZhenInsure-Skill/${SKILL_VERSION}`, Accept: "application/json", }, body: method === "POST" && body ? JSON.stringify(body) : undefined, signal: ctl.signal, }); ``` ### Technical Analysis The proxy restricts endpoint paths and HTTP methods, but it does not restrict the destination origin. `ZHENINSURE_BASE_URL` may come from action context configuration, context environment data, or the process environment. The `normBase` function only trims whitespace and trailing slashes; it does not enforce HTTPS, verify the hostname, restrict ports, or require the official ZhenInsure origin. The proxy subsequently sends the live `ZHENINSURE_API_KEY` in an `Authorization` header and forwards the request body to the selected origin. Consequently, anyone able to influence the base URL can redirect credentials and insurance consultation data to an attacker-controlled server. This behavior exceeds the minimum privileges declared in `SKILL.md`, which states that requests are forwarded directly to `https://www.zhenins.com`. The custom-origin behavior is explicitly covered by tests in `test/test-all.js:414-462`, including configuration and process-environment overrides. ### Attack Path 1. An attacker, compromised ...[truncated 1444 chars]
Remediation
## Remediation Suggestions 1. Remove the runtime base-URL override from production builds and always use the fixed official origin: ```js const baseUrl = "https://www.zhenins.com"; ``` 2. If staging support is operationally required, parse the value with `new URL()` and enforce: - `https:` only. - An exact hostname allowlist. - Approved ports only. - No embedded username or password. - No query string or fragment in the configured base URL. - A normalized origin rather than arbitrary URL concatenation. 3. Use separate credentials for production and staging so a production key is never sent to a non-production origin. 4. Disable automatic cross-origin redirects or verify the final destination before forwarding an authorization header. Sensitive authorization headers must never be forwarded to an unapproved redirect target. 5. Ensure environment and action-context configuration cannot override the trusted destination unless controlled by an authorized administrator. 6. Add negative tests proving that the proxy rejects: - Plaintext HTTP URLs. - Unapproved domains. - Look-alike and subdomain-suffix hosts. - Embedded credentials. - Unexpected ports. - Redirects to unapproved origins. 7. Update the documentation to accurately disclose any approved staging behavior and its credential-separation requirements.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
Findings (9)

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The guide explicitly shows configuring a live API key (`sk_live_abc123...`) without any warning about credential sensitivity, secret storage, shell history exposure, or least-privilege handling. In a publishing/install guide, this can normalize unsafe secret handling practices and increase the chance that users paste production credentials into insecure environments, logs, screenshots, or shared terminals.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The README explicitly demonstrates sending highly sensitive health information (for example, hypertension status and age) to a remote cloud API, but provides no privacy notice, consent guidance, data-handling explanation, or warning about transmitting special-category personal data. In an insurance context, this data is especially sensitive because it can affect underwriting and eligibility decisions, so users need clear disclosure before use.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill is explicitly designed as a transparent proxy that forwards user-supplied conversation content to an external backend while automatically attaching the operator's API key. The documentation describes this data flow but does not warn users that their messages and identifiers will leave the local environment and be processed by a third-party service, which creates a meaningful privacy and consent risk, especially for insurance-related conversations that may include sensitive personal or health information.

Natural-Language Policy Violations

Medium
Confidence
98% confidence
Finding
The skill returns user-facing error and action text in Chinese, and this pattern continues throughout the file. The policy requires flagging language or locale constraints when the skill forces a specific language without user opt-in or clear justification.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The manifest explicitly proxies insurance consultation chats and human handoff, which implies transmission of sensitive personal and potentially health-related data to a third-party service. Yet the skill description and parameters provide no user-facing warning, consent notice, retention statement, or data-sharing disclosure, increasing the risk that users disclose regulated or highly sensitive information without informed consent.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
This JavaScript test file contains multiple assertions that require response messages to include Chinese text such as "未配置", "端点不可用", "成功", and similar phrases. That encodes a single-language requirement into the skill behavior, which is a natural-language locale policy concern when no user opt-in or documented justification is present in the file.

External Transmission

Medium
Category
Data Exfiltration
Content
queueFetchResponse(200, {});

  await proxy({
    config: { ZHENINSURE_BASE_URL: "https://api.zhenins.com/" },
    args: { endpoint: "/api/v1/skill/chat/conversations", method: "POST" },
    secrets: { ZHENINSURE_API_KEY: "sk_live_12345678901234567890123456789012" },
  });
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
queueFetchResponse(200, {});

  await proxy({
    config: { ZHENINSURE_BASE_URL: "https://api.zhenins.com/" },
    args: { endpoint: "/api/v1/skill/chat/conversations", method: "POST" },
    secrets: { ZHENINSURE_API_KEY: "sk_live_12345678901234567890123456789012" },
  });
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Natural-Language Policy Violations

Low
Confidence
82% confidence
Finding
The natural-language instructions, feature descriptions, and usage guidance are presented only in Chinese. Under the policy, forcing a specific language without user opt-in or a documented justification can be a locale-policy violation.

Static analysis

Detected: suspicious.env_credential_access, suspicious.exposed_secret_literal

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
actions/proxy.js:13

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
test/test-all.js:215