T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/nightscout_read.py:11
- Finding
- Unrestricted Nightscout Base URL Enables SSRF and Insecure Transport<![CDATA[ ## Vulnerability Details **File Location**: `scripts/nightscout_read.py`, lines 11-25 **Vulnerability Type**: Server-Side Request Forgery and insecure transport **Risk Level**: High ### Vulnerable Code ```python def get_base_url() -> str: base = (sys.argv[sys.argv.index('--url') + 1] if '--url' in sys.argv and sys.argv.index('--url') + 1 < len(sys.argv) else None) or None if not base: import os base = os.environ.get('NIGHTSCOUT_BASE_URL') if not base: base = DEFAULT_BASE_URL return base.rstrip('/') + '/' def fetch_json(path: str): url = urllib.parse.urljoin(get_base_url(), path) req = urllib.request.Request(url, headers={'User-Agent': 'OpenClaw nightscout-local'}) with urllib.request.urlopen(req, timeout=20) as resp: return json.loads(resp.read().decode('utf-8')) ``` ### Technical Analysis The script accepts the base URL directly from the `--url` command-line argument or the `NIGHTSCOUT_BASE_URL` environment variable and passes the resulting URL to `urllib.request.urlopen`. It does not validate the URL scheme, hostname, resolved IP address, port, or redirect destination. An attacker able to influence either input can direct requests toward loopback, private-network, link-local, or otherwise privileged destinations reachable from the Agent's network context. Although the requested Nightscout API paths are fixed by the selected operation, an internal or attacker-controlled server can expose data at those paths or redirect the request to another destination. Python's default URL handling may follow HTTP redirects, and redirect targets are not revalidated. The script also permits plaintext HTTP. Glucose readings and related medical information can therefore be intercepted or altered by a network-positioned attacker. The returned JSON may be presented as legitimate Nightscout data. The response body is read without a maximum size, allowing a malicious server to return a very large response ...[truncated 1469 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Allow only `https` URLs and reject URLs containing embedded credentials. - Parse the URL with `urllib.parse.urlsplit` and explicitly validate the scheme, hostname, and permitted port. - Resolve the hostname and reject loopback, private, link-local, multicast, unspecified, and reserved IPv4 and IPv6 addresses. - Disable automatic redirects or revalidate the scheme, hostname, port, and resolved addresses of every redirect destination. - Consider maintaining an explicit allowlist of approved Nightscout hosts. - Require explicit operator approval before connecting to a newly supplied host. - Apply a strict response-size limit by reading the body incrementally and aborting when the maximum is exceeded. - Validate response content types and expected JSON structures before processing data. - Preserve TLS certificate verification and provide no option to disable it. ]]>
