T09 · Insecure Skill Coding Practices
Error
- Location
- bin/openclaw-aicfo-adapter.mjs:315
- Finding
- Bearer API Key Disclosure Through an Unvalidated Request Destination## Vulnerability Details **File Location**: `bin/openclaw-aicfo-adapter.mjs`, lines 20–21, 315–365, and 456–457 **Vulnerability Type**: Arbitrary credential transmission and insecure transport configuration **Risk Level**: High ### Vulnerable Code ```javascript Named options: --url <baseUrl> --api-key <token> ``` ```javascript function buildHeaders({ apiKey, companyId, contentType } = {}) { const headers = { Authorization: `Bearer ${apiKey}`, Accept: "application/json", }; if (companyId) { headers["x-company-id"] = companyId; } if (contentType) { headers["Content-Type"] = contentType; } return headers; } async function parseResponseBody(response) { const contentType = response.headers.get("content-type") ?? "application/octet-stream"; const contentDisposition = response.headers.get("content-disposition"); const text = await response.text(); let parsed = text; if (contentType.includes("application/json")) { try { parsed = text ? JSON.parse(text) : null; } catch { parsed = text; } } return { ok: response.ok, status: response.status, contentType, contentDisposition, body: parsed, }; } async function request({ appUrl, apiKey, companyId, path, method = "GET", query, jsonBody }) { const url = `${appUrl}${path}${toQueryString(query ?? {})}`; const response = await fetch(url, { method, headers: buildHeaders({ apiKey, companyId, contentType: jsonBody ? "application/json" : undefined, }), body: jsonBody ? JSON.stringify(jsonBody) : undefined, }); ``` ```javascript const appUrl = (named.url || process.env.AICFO_APP_URL || "http://localhost:3000").replace(/\/$/, ""); const apiKey = named["api-key"] || process.env.AICFO_API_KEY; ``` ### Technical Analysis The adapter accepts its destination from ei ...[truncated 3251 chars]
- Remediation
- ## Remediation Suggestions 1. **Restrict credentials to approved origins** - Parse the destination with `new URL()`. - Maintain an explicit allowlist of production API origins, such as `https://aiceo.city`. - Compare the normalized URL origin rather than using string prefix or suffix checks. - Reject embedded usernames or passwords, unexpected ports, malformed URLs, and unapproved hosts. 2. **Enforce encrypted transport** - Require `https:` for all non-loopback destinations. - If local development is required, allow plaintext HTTP only for exact loopback hosts such as `localhost`, `127.0.0.1`, or `[::1]`. - Place development exceptions behind an explicit opt-in flag rather than enabling arbitrary HTTP destinations. 3. **Use a safe default** - Use the documented production HTTPS endpoint as the production default. - Clearly separate production and local-development modes to prevent accidental credential transmission to unintended services. 4. **Constrain redirect handling** - Set `redirect: "manual"` for authenticated requests. - If redirects must be supported, validate the destination origin before issuing a new request containing credentials. - Never forward authorization headers to an origin that has not independently passed the allowlist checks. 5. **Avoid command-line secret exposure** - Remove or deprecate `--api-key`. - Obtain the key from a protected environment variable, restricted credential store, or standard input. - Ensure errors and diagnostic logs never print the key or complete authenticated request headers. 6. **Apply least privilege and credential lifecycle controls** - Issue narrowly scoped keys for only the required company and operations. - Separate read-only connector access from state-changing document or connector permissions. - Rotate the affected key if it may have been used with an untrusted destination. - Add expiry, revocation, ...[truncated 435 chars]
