T09 · Insecure Skill Coding Practices
- Location
bin/openclaw-aicfo-adapter.mjs:315- Finding
Bearer API Key Disclosure Through an Unvalidated Request Destination
- Content
View full analysis
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: HighVulnerable 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
View remediation
Remediation Suggestions
-
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.
- Parse the destination with
-
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.
- Require
-
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.
-
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.
- Set
-
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.
- Remove or deprecate
-
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]
-
