T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/query_valueset.py:46
- Finding
- Unrestricted terminology server allows sensitive query disclosure and unintended network access<![CDATA[ ## Vulnerability Details **File Location**: `scripts/query_valueset.py`, lines 46–53, 128–135, 190–197, and 342 **Vulnerability Type**: Server-Side Request Forgery risk and sensitive information disclosure **Risk Level**: Medium ### Complete Code Snippet ```python url = f"{server_url}/CodeSystem/$lookup?{parse.urlencode(params)}" try: print(f"Accessing: {url}", file=sys.stderr) req = request.Request(url) req.add_header("Accept", "application/fhir+json") with request.urlopen(req, timeout=30) as response: data = json.loads(response.read().decode()) ``` The same pattern is used for ValueSet expansion: ```python params = { "url": valueset_url } url = f"{server_url}/ValueSet/$expand?{parse.urlencode(params)}" try: print(f"Accessing: {url}", file=sys.stderr) req = request.Request(url) req.add_header("Accept", "application/fhir+json") with request.urlopen(req, timeout=30) as response: data = json.loads(response.read().decode()) ``` The server destination is supplied directly through a command-line argument: ```python parser.add_argument( "--server", default=DEFAULT_SERVER, help=f"FHIR server URL (default: {DEFAULT_SERVER})" ) ``` ### Technical Analysis The `--server` argument accepts an arbitrary URL and is concatenated directly with FHIR operation paths before being passed to `urllib.request.urlopen`. The implementation does not: - Require HTTPS. - Restrict destinations to the terminology servers documented in `SKILL.md`. - Reject loopback, private, link-local, or cloud metadata addresses. - Reject URLs containing embedded credentials. - Resolve and validate destination IP addresses. - Constrain or validate HTTP redirects. User-provided LOINC codes, search terms, and ValueSet canonical URLs are encoded into GET query strings. These values are then transmitted to the selected server and may also be exposed in proxy logs, web server logs, command output, and network monitoring syste ...[truncated 1914 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace unrestricted `--server` handling with an allowlist of approved HTTPS origins, such as: - `https://tx.fhir.org` - `https://hapi.fhir.org` - `https://r4.ontoserver.csiro.au` 2. Parse the URL with `urllib.parse.urlsplit` and reject: - Schemes other than HTTPS. - Embedded usernames or passwords. - Fragments and malformed ports. - Unexpected paths where only configured FHIR base paths should be accepted. 3. Resolve the hostname and reject loopback, private, link-local, multicast, reserved, and unspecified IP addresses using Python's `ipaddress` module. 4. Repeat destination validation after DNS resolution and before connection to reduce DNS rebinding risk. 5. Disable automatic redirects or validate every redirect target using the same scheme, host, and IP restrictions. 6. If custom servers are operationally required, make them an explicit opt-in feature and display a warning that query terms will be transmitted to that server. 7. Avoid printing full URLs containing potentially sensitive query parameters. Log only the destination host and operation name. 8. Consider using POST-based FHIR operations where supported so sensitive parameters are not placed in URLs and routine access logs. ]]>
