T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/wait_for_task.py:35
- Finding
- API Token Exposed Through GET Query Parameters## Vulnerability Details **File Location**: `scripts/wait_for_task.py`, lines 35–39, 100–107, and 128–134 **Vulnerability Type**: Sensitive 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() ``` The polling operation passes the API token as part of `params`: ```python payload = request_json( STATUS_ENDPOINT, {"api_key": api_key, "task_id": task_id}, api_key, request_timeout, ) ``` The result-download operation repeats the same credential transport: ```python if status == SUCCESS_STATUS: return request_json( DOWNLOAD_ENDPOINT, {"api_key": api_key, "task_id": task_id, "type": "json"}, api_key, request_timeout, ) ``` ### Technical Analysis `request_json` serializes every parameter into the URL and performs a GET request. Consequently, `DATAIFY_API_TOKEN` becomes part of request URLs sent to both `/task_status` and `/download`. HTTPS protects the URL from passive network observers while it is in transit, but it does not prevent the URL from being recorded at its endpoints or within trusted infrastructure. Query strings may be captured by reverse-proxy access logs, server request logs, application-performance monitoring, debugging systems, exception telemetry, or network inspection products. Replacing the API key in the response body at line 61 does not protect the request URL. The credential has already been transmitted as URL metadata before response redaction occurs. This network access is necessary for task polling, but placing the credential in a query parameter exceeds the minimum exposure ...[truncated 1099 chars]
- Remediation
- ## Remediation Suggestions 1. Remove `api_key` from all URL query parameters. 2. Send the token in an authorization header, for example: ```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. Keep only non-secret values such as `task_id` and `type` in the query string. 4. If the current Dataify API requires query-string authentication, update the service API to support authorization headers before changing the client. 5. Configure server, proxy, monitoring, and telemetry systems to redact existing `api_key` query parameters. 6. Rotate tokens that may already have appeared in request logs and establish a retention policy for historical logs. 7. Add automated tests asserting that generated request URLs never contain the API token.
