T09 · Insecure Skill Coding Practices
- Location
scripts/cloud_record.py:29- Finding
Unrestricted API Endpoint Can Redirect Sensitive Device Credentials
- Content
View full analysis
Vulnerability Details
File Location:
scripts/cloud_record.py, lines 29–30, 33–44, 58–73, 94–112, and 131–144
Vulnerability Type: Unvalidated credential destination
Risk Level: MediumVulnerable Code
python # API base address (switchable through an environment variable) JF_ENDPOINT = os.getenv("JF_ENDPOINT", "api-cn.jftechws.com") JF_BASE_URL = f"https://{JF_ENDPOINT}/gwp/v3" def get_headers(uuid: str, app_key: str, app_secret: str, move_card: int) -> Dict[str, str]: """Generate request headers containing the signature and timestamp.""" time_millis = get_time_millis() signature = generate_signature(uuid, app_key, app_secret, time_millis, move_card) return { "Content-Type": "application/json; charset=UTF-8", "uuid": uuid, "appKey": app_key, "timeMillis": time_millis, "signature": signature, "X-Request-Id": os.urandom(16).hex() }The environment-controlled endpoint is subsequently used for every authenticated request:
python url = f"{JF_BASE_URL}/rtc/device/getVideoList/{device_token}" headers = get_headers(uuid, app_key, app_secret, move_card) body = { "startTime": start_time, "stopTime": stop_time, "sn": sn, "channel": channel, "pageStart": page_start, "pageSize": page_size } if events: body["events"] = events response = requests.post(url, headers=headers, json=body, timeout=30)python url = f"{JF_BASE_URL}/rtc/device/getVideoUrl/{device_token}" headers = get_headers(uuid, app_key, app_secret, move_card) body = { "channel": channel, "fileFormat": file_format } if video_id: body["videoId"] = video_id if start_time and stop_time: body["startTime"] = start_time body["stopTime"] = stop_time if multi_video: body["multiVideo"] = "1" response = requests.post(url, headers=headers, json=body, timeou ...[truncated 3494 chars]- Remediation
View remediation
Remediation Suggestions
- Replace the raw hostname setting with a constrained region selector, such as
CN,AS,EU, orNA, and map each value internally to its approved hostname. - If
JF_ENDPOINTmust remain supported, validate it against an exact allowlist:api-cn.jftechws.comapi-as.jftechws.comapi-eu.jftechws.comapi-na.jftechws.com
- Reject values containing URL schemes, paths, query strings, fragments, user information, custom ports, IP literals, trailing-dot variants, or unapproved subdomains.
- Construct the URL only after validation and verify that the parsed hostname exactly matches the selected allowlisted hostname.
- Do not automatically follow redirects to unapproved hosts. Configure redirect handling explicitly and validate the destination of every redirect before transmitting or retransmitting authentication data.
- Avoid placing the device token in the URL where possible. If the API contract permits, transmit it in an authorization header because URLs are more likely to be retained in proxy and server logs.
- Use short-lived, narrowly scoped device tokens and enforce timestamp expiration and replay prevention on signed requests.
- Ensure deployment configuration prevents untrusted users or components from modifying the Skill process environment.
- Replace the raw hostname setting with a constrained region selector, such as
