T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/wait_for_task.py:35
- Finding
- API Token Transmitted in URL Query Parameters<![CDATA[ ## Vulnerability Details **File Location**: `scripts/wait_for_task.py:35-39, 103-107, 129-134` **Duplicate Location**: `_dependencies/skills/dataify-task-operations/scripts/wait_for_task.py` **Vulnerability Type**: Credential exposure through URL query parameters **Risk Level**: Medium ### Vulnerable Code ```python def request_json(endpoint, params, api_key, timeout): url = endpoint + "?" + urllib.parse.urlencode(params) request = urllib.request.Request(url, method="GET") try: with urllib.request.urlopen(request, timeout=timeout) as response: content = response.read() charset = response.headers.get_content_charset() or "utf-8" text = content.decode(charset, errors="replace") ``` The function is called with the API token included in `params`: ```python payload = request_json( STATUS_ENDPOINT, {"api_key": api_key, "task_id": task_id}, api_key, request_timeout, ) ``` The same behavior occurs when downloading results: ```python return request_json( DOWNLOAD_ENDPOINT, {"api_key": api_key, "task_id": task_id, "type": "json"}, api_key, request_timeout, ) ``` ### Technical Analysis The task status and result-download requests place `DATAIFY_API_TOKEN` in the URL query string. Although the destination is a fixed Dataify HTTPS endpoint, HTTPS only protects the URL while it is in transit. The complete URL can still be recorded by: - Reverse proxies and API gateways - Web server access logs - Network monitoring and observability systems - Error-reporting or tracing platforms - Debug logs generated by HTTP infrastructure - URL inspection middleware The implementation redacts the token from the response body after receiving it, but this does not protect the request URL from infrastructure logging. This also conflicts with the Skill documentation stating that tokens must not be exposed in logs. The network communication itself is necessary for the declared task-moni ...[truncated 1315 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove `api_key` from all query parameters. 2. Send the credential in an HTTP authorization header: ```python def request_json(endpoint, params, api_key, timeout): url = endpoint + "?" + urllib.parse.urlencode(params) request = urllib.request.Request( url, headers={"Authorization": "Bearer {}".format(api_key)}, method="GET", ) ``` 3. Update both status and download requests so their parameter objects contain only non-secret values such as `task_id` and `type`. 4. If the remote API does not currently support authorization headers, update the API contract before deploying the Skill. As a temporary defense, configure every relevant proxy and server to redact the `api_key` parameter. 5. Ensure exceptions, telemetry, debug output, and HTTP tracing never record authorization headers or complete sensitive URLs. 6. Rotate any tokens that may already have appeared in access logs. 7. Apply the same change to the duplicate implementation under `_dependencies/skills/dataify-task-operations/scripts/wait_for_task.py`. 8. Add an automated test asserting that the token never appears in a generated request URL. ]]>
