T09 · Insecure Skill Coding Practices
- Location
scripts/run_ppt_task.mjs:132- Finding
Arbitrary API Base Override Enables API Key and Prompt Exfiltration
- Content
View full analysis
Vulnerability Details
File Location:
scripts/run_ppt_task.mjs, lines 132–180
Vulnerability Type: Unvalidated network destination for sensitive data
Risk Level: HighVulnerable Code
js async function createTask(apiKey, apiBase, query, timeoutMs) { const payload = await fetchJson( `${apiBase}/v2/ppts`, { method: 'POST', headers: { Accept: 'application/json', Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ query }), }, timeoutMs ); const data = payload?.data ?? {}; if (!data.task_id) { throw new Error('Unexpected response: missing task_id'); } return data; } async function queryHistorical(apiKey, apiBase, taskId, timeoutMs) { const payload = await fetchJson( `${apiBase}/v2/tasks/${encodeURIComponent(taskId)}/historical`, { method: 'GET', headers: { Accept: 'application/json', Authorization: `Bearer ${apiKey}`, }, }, timeoutMs ); return payload?.data ?? {}; } async function main() { const args = parseArgs(process.argv.slice(2)); if (args.help) { usage(); process.exit(0); } if (!args.query) { usage(); process.exit(1); } const apiKey = process.env.FELO_API_KEY?.trim(); if (!apiKey) { console.error('ERROR: FELO_API_KEY not set'); process.exit(1); } const apiBase = (process.env.FELO_API_BASE?.trim() || DEFAULT_API_BASE).replace(/\/$/, '');Technical Analysis
The documented destination for this Skill is the fixed Felo API origin,
https://openapi.felo.ai. However, the implementation permits theFELO_API_BASEenvironment variable to replace that origin without validating its scheme, hostname, port, or trust level.Both
createTask()andqueryHistorical()attach the production `FELO_API_K ...[truncated 2324 chars]- Remediation
View remediation
Remediation Suggestions
-
Remove the
FELO_API_BASEoverride and always use the fixed official origin:js const apiBase = 'https://openapi.felo.ai'; -
If endpoint configurability is operationally required, parse and validate the URL before making any request:
js const OFFICIAL_API_ORIGIN = 'https://openapi.felo.ai'; const candidate = new URL( process.env.FELO_API_BASE?.trim() || OFFICIAL_API_ORIGIN ); if (candidate.origin !== OFFICIAL_API_ORIGIN) { throw new Error('FELO_API_BASE must use the official Felo API origin'); } const apiBase = candidate.origin; -
Require HTTPS explicitly and reject alternate protocols, embedded credentials, unexpected ports, and hostname suffix tricks. Exact origin comparison is preferable to suffix matching.
-
Bind credential attachment to the approved origin inside the request helper. Before adding the
Authorizationheader, verify that the final request URL uses the exact trusted origin. This provides defense in depth if URL construction changes later. -
Do not follow cross-origin redirects while carrying authorization credentials. Configure redirect handling explicitly and reject redirects to any origin other than the approved Felo API.
-
If a non-production endpoint is genuinely needed for testing, require an explicit development mode and separate test credentials. Production
FELO_API_KEYvalues must never be sent to custom endpoints. -
Document that presentation prompts are transmitted to Felo and advise users not to include secrets or regulated data unless approved under their organization’s data-handling policy.
-
Rotate any API key that may have been used while
FELO_API_BASEpointed to an untrusted destination, and review associated API activity for unauthorized use.
-
