T09 · Insecure Skill Coding Practices
Error
- Location
- references/api-guide.md:264
- Finding
- API Credentials Exposed to an LLM and Unvalidated LLM-Generated Requests<![CDATA[ ## Vulnerability Details **File Location**: `references/api-guide.md:44-72, 74-124, 264-292`; `SKILL.md:78-97, 197-209` **Vulnerability Type**: Indirect prompt injection, credential disclosure, and server-side request forgery **Risk Level**: High ### Vulnerable Code ```javascript // Get API key from the environment const apiKey = process.env[sportsAPI.apiKeyEnvVar]; ``` The prompt template places the credential and attacker-controlled query in the same LLM context: ```text API Configuration: - Name: {api.name} - Base URL: {api.baseUrl} - API Key Location: {api.apiKeyLocation} - API Key: {apiKey} - Free API Key Available: {api.freeApiKey ? `Yes (${api.freeApiKey})` : 'No'} - Category: {api.category} - Default Parameters: {api.defaultParams ? JSON.stringify(api.defaultParams) + ' (ALWAYS include these in API calls)' : 'None'} API Documentation: {apiDocs} User Query: "{query}" Return JSON with the API call details: { "method": "GET" or "POST", "url": "full URL with parameters", "headers": {}, "body": null or object for POST } ``` The complete request-construction flow then executes the LLM-generated destination directly: ```javascript // 3. Get API key let apiKey = process.env[api.apiKeyEnvVar]; if (!apiKey && api.freeApiKey) { apiKey = api.freeApiKey; } // 4. Use LLM to construct API call const apiCallPlan = await llmClient.constructAPICall({ query, apiDocs, apiConfig: api, apiKey }); // 5. Execute API call const response = await axios({ method: apiCallPlan.method, url: apiCallPlan.url, headers: apiCallPlan.headers || {}, data: apiCallPlan.body || null }); ``` ### Technical Analysis Oracle query text is obtained from IPFS content referenced by a public blockchain event. A requester can therefore control the text passed as `query`. The implementation sends that untrusted text to the same LLM context that contains a raw API key. It subsequently trusts the LLM to generate the complete HTTP method, URL, headers, and b ...[truncated 2386 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Never place raw API keys in an LLM prompt or LLM tool result. 2. Require the LLM to return a narrow structured plan containing only: - A predefined endpoint identifier - Validated non-sensitive query parameters - A bounded pagination value 3. Construct the final request in trusted application code. 4. Inject credentials only after all destination validation succeeds. 5. Enforce an exact allowlist of schemes, hostnames, ports, and paths derived from trusted configuration. 6. Permit HTTPS only and reject URLs containing user information or unexpected ports. 7. Resolve destination hostnames and reject loopback, private, link-local, multicast, and reserved IP ranges. 8. Disable redirects, or revalidate every redirect destination before following it. 9. Prefer API-key headers over URL query parameters or URL paths to reduce leakage through logs. 10. Restrict methods to `GET` unless a specific endpoint has been reviewed and explicitly allows another method. 11. Treat IPFS queries and API documentation as untrusted data, not instructions. 12. Add prompt-injection tests that attempt credential extraction, hostname substitution, redirect abuse, and access to metadata endpoints. ]]>
