T09 · Insecure Skill Coding Practices
- Location
scripts/wait_for_task.py:35- Finding
Long-Lived API Token Exposed in HTTP Query Strings
- Content
View full analysis
Vulnerability Details
File Location:
scripts/wait_for_task.py, lines 35–37, with credential-bearing calls at lines 105–109 and 130–134
Vulnerability Type: Sensitive credential exposure through request URLs
Risk Level: MediumVulnerable Code
python def request_json(endpoint, params, api_key, timeout): url = endpoint + "?" + urllib.parse.urlencode(params) request = urllib.request.Request(url, method="GET")The API token is supplied as an
api_keyquery parameter when polling task status:python payload = request_json( STATUS_ENDPOINT, {"api_key": api_key, "task_id": task_id}, api_key, request_timeout, )It is supplied in the same manner 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
request_json()serializes all parameters into the URL of a GET request. Consequently, the long-livedDATAIFY_API_TOKENbecomes part of every status and download URL.HTTPS protects the request from passive network interception while in transit, but it does not prevent the complete URL from being recorded by the Dataify service, reverse proxies, gateways, request tracing systems, application-performance monitoring tools, browser-like network instrumentation, or exception diagnostics. Query strings are commonly retained in access logs.
The response-body redaction performed later in
request_json()does not protect the outgoing request URL. The behavior is necessary only to authenticate task operations; placing the credential in the query string is not necessary if the service supports authorization headers or authenticated POST bodies.Attack Path
- A user configures a valid
DATAIFY_API_TOKENand submits a collection task. - The Skill begins polling the status endpoint.
- `reques ...[truncated 831 chars]
- A user configures a valid
- Remediation
View remediation
Remediation Suggestions
-
Replace the
api_keyquery parameter with 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", ) -
Keep only non-sensitive values such as
task_idand result type in the query string. -
If the API does not support bearer headers, use an authenticated POST body and ensure request-body logging is disabled or redacted.
-
Configure server, proxy, and telemetry systems to redact
api_key,token, and authorization values. -
Avoid including full credential-bearing URLs in errors, diagnostics, or progress output.
-
Rotate tokens that may already have appeared in request logs.
-
Prefer narrowly scoped, revocable tokens with account-level rate and spending limits.
-
