T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/wait_for_task.py:35
- Finding
- API Token Exposed in URL Query Strings## Vulnerability Details **File Location**: `scripts/wait_for_task.py`, lines 35–39, with vulnerable calls at lines 103–107 and 129–133 **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: ``` The function is called with the API token inside `params`: ```python payload = request_json( STATUS_ENDPOINT, {"api_key": api_key, "task_id": task_id}, api_key, request_timeout, ) ``` The same pattern is used to download the completed task: ```python return request_json( DOWNLOAD_ENDPOINT, {"api_key": api_key, "task_id": task_id, "type": "json"}, api_key, request_timeout, ) ``` ### Technical Analysis The task poller puts `DATAIFY_API_TOKEN` directly into the query string of requests to `/task_status` and `/download`. HTTPS encrypts the URL while it is in transit, but it does not prevent the complete URL from being recorded at endpoints or intermediaries that terminate or observe the request. Query strings are commonly retained in web-server access logs, reverse-proxy logs, application performance monitoring systems, debugging traces, browser or client diagnostics, and exception telemetry. The following response-body replacement does not protect the request URL: ```python if api_key: text = text.replace(api_key, "<redacted>") ``` This replacement occurs only after receiving a response and therefore cannot remove the credential from infrastructure logs created while processing the request. The behavior is not necessary for the declared functionality. Other project clients already authenticate safely with an `Authorization: Bearer ...` header. ### Attack Path 1. A user configures a valid `DA ...[truncated 1087 chars]
- Remediation
- ## Remediation Suggestions - Remove `api_key` from all query parameter dictionaries. - Send the credential through 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", ) ``` - If the API does not support bearer authentication for these endpoints, use a POST body rather than the URL and update the service contract accordingly. - Keep only non-secret values such as `task_id` and `type` in the query string. - Apply centralized URL and header redaction to HTTP diagnostics, exceptions, tracing, and telemetry. - Rotate tokens that may already have appeared in request logs. - Configure server, proxy, and monitoring systems not to record authorization headers or sensitive query parameters.
