T09 · Insecure Skill Coding Practices
- Location
scripts/qas_client.py:64- Finding
API Token Exposed in URL Query Strings and Potentially Transmitted over Plaintext HTTP
- Content
View full analysis
dict: """GET request to QAS API""" url = f"{QAS_BASE_URL}{endpoint}" params = params or {} params["token"] = QAS_TOKEN query = urllib.parse.urlencode(params) full_url = f"{url}?{query}" if params else url try: resp = urllib.request.urlopen(full_url, timeout=30) return json.loads(resp.read().decode("utf-8")) except urllib.error.HTTPError as e: return {"success": False, "message": f"HTTP {e.code}: {e.reason}"} except Exception as e: return {"success": False, "message": str(e)} def post(endpoint: str, data: dict = {}, raw: bool = False) -> dict: """POST request to QAS API - token must be in query param, not body""" url = f"{QAS_BASE_URL}{endpoint}" data = data or {} # Token goes in query param, NOT in body (server ignores token in body) query = f"token={QAS_TOKEN}" full_url = f"{url}?{query}" json_data = json.dumps(data).encode("utf-8") req = urllib.request.Request( full_url, data=json_data, headers={"Content-Type": "application/json"} ) try: resp = urllib.request.urlopen(req, timeout=30) ``` The documentation also explicitly permits an HTTP endpoint: ```markdown - `QAS_BASE_URL` - User provided, e.g., http://192.168.1.x:5005 ``` ### Technical Analysis Every GET and POST request appends `QAS_TOKEN` to the request URL. URLs are routinely retained in reverse-proxy access logs, web server logs, monitoring systems, browser or intermediary diagnostics, and error telemetry. Anyone who can read those records may recover the credential. The client does not validate the scheme, host, or trustworthiness of `QAS_BASE_URL`. Because `SKILL.md` gives a plaintext HTTP UR ...[truncated 1640 chars]- Remediation
View remediation
