T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/wait_for_task.py:30
- Finding
- API Token Exposed in URL Query Parameters<![CDATA[ ## Vulnerability Details **File Location**: `scripts/wait_for_task.py:30-39`, with vulnerable calls at `scripts/wait_for_task.py:100-105` and `scripts/wait_for_task.py:124-129` **Vulnerability Type**: Sensitive credential exposure through request URLs **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 invoked 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 `DATAIFY_API_TOKEN` value is serialized into the query string of GET requests. Although the requests use HTTPS and are sent to the declared Dataify domain, HTTPS only protects the request in transit. It does not prevent complete URLs from being recorded by the destination server, reverse proxies, API gateways, observability systems, browser or HTTP debugging tools, network security products, or exception-reporting infrastructure. The response-body redaction performed later by the function does not protect request metadata: ```python if api_key: text = text.replace(api_key, "<redacted>") ``` This replacement only applies to the received response text. It cannot remove the token from access logs or telemetry generated before or during request processing. The token is required for legitima ...[truncated 1419 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove `api_key` from all URL query parameters. 2. Transmit the credential using an 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. Retain only non-secret values such as `task_id` and `type` in the query string. 4. If the provider does not support authorization headers, use a POST body where supported and document the residual logging risk. 5. Configure application, proxy, and API gateway logging to redact authorization headers and known secret fields. 6. Rotate any tokens that may already have appeared in URL logs. 7. Add tests asserting that generated request URLs never contain the API token or an `api_key` parameter. ]]>
