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.
