T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/skill_router.py:48
- Finding
- Media.io API Key May Leak Through Unvalidated Cross-Origin Redirects<![CDATA[ ## Vulnerability Details **File Location**: `scripts/skill_router.py`, lines 48–65 **Vulnerability Type**: Credential disclosure through automatic redirect handling **Risk Level**: Medium ### Vulnerable Code ```python api = self.api_definitions[api_name] url = api['endpoint'] method = api['method'] parsed = urlparse(url) if parsed.scheme != 'https' or parsed.netloc.lower() != 'openapi.media.io': return {'error': f"Blocked endpoint host: {parsed.netloc}"} headers = { 'X-API-KEY': resolved_api_key, 'Content-Type': 'application/json' } if '{' in url: for k, v in params.items(): url = url.replace(f'{{{k}}}', str(v)) body = {k: v for k, v in params.items() if f'{{{k}}}' not in api['endpoint']} try: resp = requests.request(method, url, headers=headers, json={'data': body} if body else {}, timeout=30) ``` ### Technical Analysis The implementation validates the scheme and hostname of the initial endpoint, restricting it to HTTPS requests sent to `openapi.media.io`. However, `requests.request()` follows HTTP redirects by default, and the code does not validate redirect destinations. The credential is transmitted in the custom `X-API-KEY` header. Cross-origin redirect protection commonly associated with the standard `Authorization` header does not reliably protect arbitrary custom authentication headers. Consequently, a redirect to a different origin may cause the API key to be included in the redirected request. The initial endpoint is fixed by the bundled API definition, so exploitation requires the approved Media.io endpoint, its infrastructure, or an upstream component to be compromised or misconfigured so that it returns an attacker-controlled redirect. A redirect status that preserves the HTTP method and body, such as HTTP 307 or 308, could also disclose submitted business parameters. ### Attack Path 1. An attacker compromises or influences `openapi.media.io`, a relevant upstream service, or its redirect configuration. ...[truncated 1286 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Disable automatic redirect handling for authenticated API requests: ```python resp = requests.request( method, url, headers=headers, json={'data': body} if body else {}, timeout=30, allow_redirects=False, ) ``` If redirects are required, implement explicit redirect processing: 1. Inspect each `Location` header without automatically following it. 2. Resolve relative redirects safely against the current URL. 3. Require the destination scheme to remain `https`. 4. Require the normalized destination hostname to equal `openapi.media.io`. 5. Consider restricting redirects to the same origin, including the expected port. 6. Set a small maximum redirect count to prevent loops. 7. Never forward `X-API-KEY` or other sensitive headers when the origin changes. 8. Reject malformed URLs, URLs containing user information, and unexpected ports. 9. Add automated tests covering cross-host 301, 302, 303, 307, and 308 responses and verify that credentials are never sent to an unapproved origin. ]]>
