T09 · Insecure Skill Coding Practices
- Location
scripts/qweather_utils.py:100- Finding
JWT bearer token can be transmitted to an arbitrary or plaintext HTTP host
- Content
View full analysis
str: val = arg_val or os.environ.get(env_var) if not val: print(f"Error: missing {description}", file=sys.stderr) print(f"Set environment variable {env_var} or pass it as an argument", file=sys.stderr) sys.exit(1) val = val.strip().rstrip("/") if not val.startswith(("http://", "https://")): val = "https://" + val return val ``` The resulting host is used to construct authenticated requests: ```python url = f"{host}/geo/v2/city/lookup?location={urllib.parse.quote(city_name)}&number=1" headers = { "Authorization": f"Bearer {token}", "Accept": "application/json", } result = api_get(url, headers, log_prefix="qweather-geo") ``` The same pattern appears in each weather endpoint: ```python url = f"{host}/v7/weather/now?location={location_id}" headers = { "Authorization": f"Bearer {token}", "Accept": "application/json", } return api_get(url, headers, log_prefix="qweather-get-weather-now") ``` ```python req_headers = dict(headers) req_headers["Accept-Encoding"] = "gzip" req = urllib.request.Request(url, headers=req_headers) try: with urllib.request.urlopen(req, timeout=15) as resp: ``` ### Technical Analysis The API host can come from either the `--host` command-line argument or the `QWEATHER_API_HOST` environment variable. Validation only checks whether the value begins with `http://` or `https://`; it does not: - Require TLS. - Restrict the destination to an authorized QWeather domain. - Reject IP literals, unexpected p ...[truncated 2011 chars]- Remediation
View remediation
