T09 · Insecure Skill Coding Practices
Error
- Location
- rss_reader.py:33
- Finding
- API Credential Disclosure Through an Unrestricted AI Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `rss_reader.py:33-35, 349-354, 596-604` **Vulnerability Type**: User-configurable credential transmission destination **Risk Level**: High ### Vulnerable Code ```python OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "") OPENAI_BASE_URL = os.getenv( "OPENAI_BASE_URL", "https://open.bigmodel.cn/api/paas/v4" ) FEISHU_WEBHOOK_URL = os.getenv("FEISHU_WEBHOOK_URL", "") ``` ```python response = requests.post( f"{OPENAI_BASE_URL}/chat/completions", headers={ "Authorization": f"Bearer {OPENAI_API_KEY}", "Content-Type": "application/json" }, ``` The daily-report implementation has the same issue: ```python base_url = os.getenv( "OPENAI_BASE_URL", "https://open.bigmodel.cn/api/paas/v4" ) api_url = ( base_url if base_url.endswith("/chat/completions") else f"{base_url}/chat/completions" ) response = requests.post( api_url, headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, ``` ### Technical Analysis The Skill obtains an AI API credential from `OPENAI_API_KEY` and transmits it as a bearer token to a destination derived directly from `OPENAI_BASE_URL`. The code does not validate the URL scheme, hostname, port, resolved address, redirect target, or trusted provider identity. Sending a credential to the configured AI provider is necessary for the declared summarization feature. However, allowing the credential destination to be any arbitrary URL exceeds the minimum privilege required. Anyone able to modify the Gateway environment or process environment can redirect the request to a server they control. The same unrestricted destination is used by single-article summaries, batch summaries, and daily reports. Requests may also contain article titles, descriptions, and source metadata. ### Attack Path 1. The attacker gains an ability to influence the Skill's environment or Gateway configuration. 2. The ...[truncated 977 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Require an HTTPS endpoint and reject plaintext HTTP. 2. Maintain an explicit allowlist of supported provider origins, including the expected scheme, hostname, and port. 3. Parse URLs with `urllib.parse.urlparse` rather than validating them with string prefixes. 4. Reject embedded credentials, fragments, unexpected ports, IP literals, localhost, and private, loopback, link-local, multicast, or reserved addresses. 5. Disable redirects or validate every redirect destination before forwarding a request containing credentials. 6. Resolve the hostname and validate all returned addresses immediately before connecting to mitigate DNS rebinding. 7. Use provider-specific credential variables so a credential intended for one provider cannot be sent to another provider. 8. Avoid placing bearer tokens into a request until the final destination has passed validation. 9. Document that changing the endpoint changes the party receiving both the API key and submitted content. ]]>
