T09 · Insecure Skill Coding Practices
- Location
scripts/smart_alarm.py:27- Finding
Unvalidated API Endpoint Allows Credential and Device-Token Disclosure
- Content
View full analysis
Vulnerability Details
File Location:
scripts/smart_alarm.py, lines 27–28, 31–43, and network request sites at lines 55–58, 119–123, 154–158, 175–179, 294–310, and 327–349
Vulnerability Type: Arbitrary destination for sensitive authenticated requests
Risk Level: HighVulnerable Code
The destination hostname is taken directly from an environment variable without validation:
python # API 基础地址(可通过环境变量切换) JF_ENDPOINT = os.getenv("JF_ENDPOINT", "api-cn.jftechws.com") JF_BASE_URL = f"https://{JF_ENDPOINT}/gwp/v3"Every request includes authentication-related headers derived from sensitive application credentials:
python def get_headers(uuid: str, app_key: str, app_secret: str, move_card: int) -> Dict[str, str]: """生成请求头(包含签名和时间戳)""" 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() }Device tokens are included in URLs sent to the selected host. For example:
python def get_device_ability(device_token: str, uuid: str, app_key: str, app_secret: str, move_card: int) -> Dict[str, Any]: """ 获取设备能力集 Returns: 能力集数据 """ url = f"{JF_BASE_URL}/rtc/device/getability/{device_token}" headers = get_headers(uuid, app_key, app_secret, move_card) response = requests.post(url, headers=headers, timeout=30) result = response.json() if result.get("code") != 2000: raise RuntimeError(f"获取能力集失败:{result.get('msg', '未知错误')}") return result.get("data", {})Alarm query details are also sent to the selected destination:
python def get_ala ...[truncated 4341 chars]- Remediation
View remediation
Remediation Suggestions
-
Replace the raw
JF_ENDPOINTsetting with a constrained region selector and an internal mapping:python OFFICIAL_ENDPOINTS = { "CN": "api-cn.jftechws.com", "AS": "api-as.jftechws.com", "EU": "api-eu.jftechws.com", "NA": "api-na.jftechws.com", "SA": "api-sa.jftechws.com", "RU": "api-ru.jftechws.com", "AF": "api-af.jftechws.com", "OC": "api-oc.jftechws.com", } region = os.getenv("JF_REGION", "CN").upper() if region not in OFFICIAL_ENDPOINTS: raise RuntimeError("Unsupported JF API region") JF_BASE_URL = f"https://{OFFICIAL_ENDPOINTS[region]}/gwp/v3" -
If hostname configuration must be retained, compare the parsed hostname against an exact allowlist. Reject subdomains, user-information components, explicit ports, paths, query strings, fragments, IP literals, and redirects to unapproved hosts.
-
Configure
requestsnot to follow redirects automatically for authenticated calls, or validate every redirect destination before forwarding sensitive headers:python response = requests.post( url, headers=headers, json=body, timeout=30, allow_redirects=False, ) -
Where supported by the API, move the device token out of the URL path and into an authorization header. URLs are more likely to appear in proxy, server, monitoring, and exception logs.
-
Use narrowly scoped, short-lived device tokens and rotate a token immediately if it may have been transmitted to an untrusted endpoint.
-
Add tests confirming that unsupported regions, arbitrary domains, deceptive suffixes such as
api-cn.jftechws.com.attacker.example, URL user information, IP addresses, and nonstandard ports are rejected before any request is made. -
Document the exact permitted remote hosts and ensure deployment policy prevents untrusted users or wrappers from alteri ...[truncated 42 chars]
-
