T09 · Insecure Skill Coding Practices
- Location
scripts/task-inspector.js:33- Finding
Unvalidated API Base URL Can Expose the WeryAI Bearer Credential
- Content
View full analysis
Vulnerability Details
File Location:
scripts/task-inspector.js:33-38andscripts/vendor/weryai-core/client.js:4-17, 38-43
Vulnerability Type: Unvalidated credential destination
Risk Level: MediumVulnerable Code
js function createContext(verbose) { return { apiKey: process.env.WERYAI_API_KEY || '', baseUrl: process.env.WERYAI_BASE_URL || 'https://api.weryai.com', verbose, requestTimeoutMs: Number(process.env.WERYAI_REQUEST_TIMEOUT_MS) || 30_000, }; }js export function createClient(ctx) { const { apiKey, baseUrl, requestTimeoutMs, verbose } = ctx; async function request(method, path, body = null, { retries = 0 } = {}) { if (!apiKey) { throw Object.assign( new Error('Missing API key environment variable.'), { code: 'NO_API_KEY' }, ); } const url = `${baseUrl}${path}`; const headers = { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json', }; // ... const res = await fetch(url, { method, headers, body: body ? JSON.stringify(body) : undefined, signal: controller.signal, });Technical Analysis
The client accepts
WERYAI_BASE_URLfrom the process environment and uses it directly to construct the request destination. It does not parse or validate the URL, require HTTPS, or verify that the hostname belongs to the official WeryAI service.The same request unconditionally attaches
WERYAI_API_KEYas anAuthorization: Bearerheader. Consequently, control overWERYAI_BASE_URLis equivalent to control over the destination receiving the credential.This behavior also weakens the documented trust boundary that the skill uses official WeryAI endpoints. Although exploitation requires influence over the runtime environment, environment variables may be supplied through wrappers, automation configuration, container settings, or inherited shell state.
Attack Path
- An attacker gain ...[truncated 1176 chars]
- Remediation
View remediation
Remediation Suggestions
- Remove the
WERYAI_BASE_URLoverride if custom API origins are not a supported requirement. - If an override is required, parse it with
new URL()and reject malformed values. - Require the
https:protocol. - Allowlist the exact official hostname or a narrowly defined set of trusted WeryAI hostnames.
- Reject embedded credentials, unexpected ports, fragments, and non-root path prefixes unless explicitly required.
- Validate the final request URL again immediately before attaching the bearer header.
- Attach
Authorizationonly when the final URL matches the trusted origin. - Fail closed with a clear configuration error when validation fails.
- Add automated tests covering attacker-controlled domains, HTTP URLs, deceptive subdomains, user-information syntax, and unexpected ports.
Example hardening:
js const OFFICIAL_ORIGIN = 'https://api.weryai.com'; function validateBaseUrl(value) { const url = new URL(value); if (url.origin !== OFFICIAL_ORIGIN) { throw new Error('WERYAI_BASE_URL must use the official WeryAI API origin.'); } if (url.username || url.password || url.search || url.hash) { throw new Error('Invalid WERYAI_BASE_URL.'); } return url.origin; }- Remove the
