T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/batch_search.py:326
- Finding
- Configurable LLM endpoint can receive sensitive queries and bearer credentials<![CDATA[ ## Vulnerability Details **File Location**: `scripts/batch_search.py:326-335`, `scripts/batch_search.py:986-988` **Vulnerability Type**: Arbitrary remote endpoint and sensitive-data transmission **Risk Level**: High ### Vulnerable Code ```python def call_llm(api_url, api_key, model, messages, temperature=0.1, timeout=30): """Call an OpenAI-compatible LLM API.""" try: import requests resp = requests.post( api_url, json={"model": model, "messages": messages, "temperature": temperature, "max_tokens": 2048}, headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}, timeout=timeout, ) resp.raise_for_status() ``` The endpoint, credential, and model are supplied through command-line arguments: ```python parser.add_argument("--api-key", type=str, default="", help="LLM API Key") parser.add_argument("--api-url", type=str, default="https://openrouter.ai/api/v1/chat/completions", help="LLM API URL") parser.add_argument("--model", type=str, default="deepseek/deepseek-chat-v3-0324", help="LLM model name") ``` ### Technical Analysis The script sends the complete `messages` payload to the endpoint selected through `--api-url` and places the user-supplied API key in the HTTP `Authorization` header. There is no endpoint allowlist, hostname validation, or restriction requiring the configured URL to use HTTPS. Depending on the search stage, transmitted messages can include: - User-supplied product and material names. - Chemical names, translations, and decomposition requests. - Alternative-product requests. - Up to ten or fifteen matched ecoinvent records in strict validation and filtering mode. - The bearer API credential itself. The Skill is declared primarily as a local database-search capability, and the documented workflow states that the Agent should run the script with `--no-llm`. Consequently, remote network access is not necessary for its min ...[truncated 1656 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove remote LLM support from this local-search Skill if it is not required for the declared functionality. 2. If remote mode must remain, require an explicit opt-in flag such as `--enable-remote-llm`; do not make remote processing the operational default. 3. Restrict endpoints to an explicit allowlist of trusted HTTPS origins. 4. Reject non-HTTPS URLs, embedded credentials, redirects to untrusted origins, loopback addresses, link-local addresses, and private-network destinations unless specifically required. 5. Disable redirects or independently validate every redirect target before forwarding the authorization header. 6. Read credentials from a protected environment variable, operating-system secret store, or non-echoing prompt rather than a command-line argument. 7. Display a clear consent notice listing the exact data fields that will leave the system. 8. Minimize prompts by excluding database records and other details that are unnecessary for the requested LLM operation. 9. Use separate, narrowly scoped, revocable API credentials with strict spending and rate limits. 10. Ensure errors and debug logs never record authorization headers or full sensitive prompts. ]]>
