T09 · Insecure Skill Coding Practices
- Location
scripts/wait_for_task.py:35- Finding
API Token Exposed in URL Query Strings
- Content
View full analysis
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: MediumComplete Code Snippet
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 function receives the API credential inside
paramsat both call sites:python payload = request_json( STATUS_ENDPOINT, {"api_key": api_key, "task_id": task_id}, api_key, request_timeout, )python return request_json( DOWNLOAD_ENDPOINT, {"api_key": api_key, "task_id": task_id, "type": "json"}, api_key, request_timeout, )Technical Analysis
The task polling and download requests place
DATAIFY_API_TOKENdirectly in the URL query string. Although the endpoints use HTTPS, HTTPS only protects the request while it is in transit. It does not prevent the complete URL from being recorded by the Dataify service, reverse proxies, load balancers, web-server access logs, observability products, exception telemetry, or debugging tools.The response-body redaction performed later in the function does not protect the request URL:
python if api_key: text = text.replace(api_key, "<redacted>")This replacement only sanitizes returned response text. It cannot remove credentials already captured from the outbound URL.
Using a secret as a query parameter also gives the credential broader exposure than required. Other project requests authenticate through an
Authorization: Bearerheader, demonstrating a safer design that should also be used here.Attack Path
- A user configures a valid
DATAIFY_API_TOKENin the process environmen ...[truncated 1295 chars]
- A user configures a valid
- Remediation
View remediation
Remediation Suggestions
- Remove
api_keyfrom all query-parameter mappings. - 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", ) with urllib.request.urlopen(request, timeout=timeout) as response: # Process the response. ...- Change the call sites to include only non-secret parameters:
python payload = request_json( STATUS_ENDPOINT, {"task_id": task_id}, api_key, request_timeout, )python return request_json( DOWNLOAD_ENDPOINT, {"task_id": task_id, "type": "json"}, api_key, request_timeout, )- If these API endpoints do not support authorization headers, update the service contract to support them. As a temporary fallback, use a POST body rather than a query string, while recognizing that authorization headers remain preferable.
- Ensure HTTP clients, proxies, and telemetry systems redact
Authorizationheaders. - Review existing access, proxy, and observability logs for leaked tokens. Apply restricted retention and access controls, purge exposed records where feasible, and rotate affected credentials.
- Add automated tests asserting that generated request URLs never contain
api_key,token, or the configured credential value.
- Remove
