T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/run_ppt_task.mjs:179
- Finding
- Unrestricted API Base Override Can Expose API Credentials and User Prompts<![CDATA[ ## Vulnerability Details **File Location**: `scripts/run_ppt_task.mjs:139-173, 179-185` **Vulnerability Type**: Unvalidated network destination for sensitive data **Risk Level**: High ### Vulnerable Code ```js async function createTask(apiKey, apiBase, query, timeoutMs, theme) { const reqBody = { query }; if (theme) { reqBody.ppt_config = { ai_theme_id: theme }; } const payload = await fetchJson( `${apiBase}/v2/ppts`, { method: 'POST', headers: { Accept: 'application/json', Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json', }, body: JSON.stringify(reqBody), }, 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 ?? {}; } ``` ```js 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 script obtains the sensitive `FELO_API_KEY` environment variable and sends it in the `Authorization` header to the URL selected through `FELO_API_BASE`. The same destination receives the complete presentation prompt through the task-creation request. The value of `FELO_API_BASE` is not validated. In particular, the implementation does not: - Require HTTPS. - Restrict the hostname to an approved Felo API domain. - Reject URLs containing embedded credentials or unexpected components. - Prevent requests to attacker-controlled, ...[truncated 1847 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove support for `FELO_API_BASE` if a custom API endpoint is not an explicit functional requirement. 2. If endpoint customization is required, parse it with the `URL` class and enforce: - `https:` as the only permitted protocol. - An explicit allowlist of trusted hostnames, preferably only `openapi.felo.ai`. - No username or password URL components. - No unexpected path, query, or fragment components in the configured base URL. 3. Disable automatic redirects or validate every redirect target before forwarding the `Authorization` header. 4. Never forward bearer credentials across origins. 5. Fail closed with a clear error when endpoint validation fails. 6. Document that prompts are transmitted to Felo and advise users not to include unnecessary secrets or regulated data. 7. Consider separating development endpoint support into an explicit command-line option that requires affirmative user consent rather than implicitly trusting an environment variable. Example validation: ```js function validateApiBase(value) { const url = new URL(value || DEFAULT_API_BASE); if ( url.protocol !== 'https:' || url.hostname !== 'openapi.felo.ai' || url.username || url.password || url.search || url.hash ) { throw new Error('FELO_API_BASE must use the approved HTTPS Felo API endpoint'); } return url.origin; } ``` ]]>
