T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/fetch_afad_earthquakes.py:37
- Finding
- Unrestricted Source URL Override Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fetch_afad_earthquakes.py:37`, `scripts/fetch_afad_earthquakes.py:211-232`, and `scripts/fetch_afad_earthquakes.py:345-352` **Vulnerability Type**: Server-Side Request Forgery through an unrestricted user-controlled URL **Risk Level**: Medium ### Vulnerable Code ```python # scripts/fetch_afad_earthquakes.py:37 parser.add_argument("--source-url", default=DEFAULT_SOURCE_URL) ``` ```python # scripts/fetch_afad_earthquakes.py:211-232 def fetch_events( source_url: str, timeout: int, window: timedelta | None, ) -> list[dict[str, Any]]: url = build_url(source_url=source_url, window=window) request = Request( url, headers={ "Accept": "application/json", "User-Agent": "turkiye-afad-deprem-skill/0.1", }, method="GET", ) try: with urlopen(request, timeout=timeout) as response: status = getattr(response, "status", 200) if int(status) >= 400: raise AppError( "HTTP_ERROR", f"AFAD servisi HTTP {status} dondu", exit_code=4, ) ``` ```python # scripts/fetch_afad_earthquakes.py:345-352 if args.fixture: raw_events = load_fixture(args.fixture) else: raw_events = fetch_events( source_url=args.source_url, timeout=args.timeout, window=window, ) ``` ### Technical Analysis The `--source-url` command-line argument is passed directly into `build_url()` and then to `urllib.request.urlopen()` without validating the URL scheme, destination hostname, port, or resolved IP address. The implementation does not restrict requests to the documented AFAD endpoint. Consequently, a caller who can influence invocation arguments can cause the process to issue HTTP GET requests to arbitrary reachable services. Potential destinations include loopback addresses, private network ranges, link-local a ...[truncated 2461 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Remove the endpoint override in production** - Use the fixed AFAD endpoint when arbitrary endpoint selection is not an explicit requirement. - Keep fixture-based operation limited to controlled testing environments. 2. **Apply an exact destination allowlist** - Require the `https` scheme. - Permit only the expected hostname, such as `deprem.afad.gov.tr`. - Reject embedded credentials, unexpected ports, malformed hostnames, and alternate representations of the destination. 3. **Validate resolved addresses** - Resolve the hostname before connecting. - Reject loopback, private, link-local, multicast, reserved, and unspecified IPv4 and IPv6 addresses. - Account for hosts that return multiple addresses and DNS rebinding between validation and connection. 4. **Control redirects** - Prefer disabling redirects. - If redirects are required, validate the scheme, hostname, port, and resolved address of every redirect target before following it. 5. **Enforce outbound network restrictions** - At deployment level, restrict the process to the AFAD host using firewall, proxy, container, or sandbox egress rules. - Block access to private networks and cloud metadata addresses independently of application validation. 6. **Add security regression tests** - Verify rejection of `http`, loopback, private IPv4, private IPv6, link-local, credential-bearing URLs, nonstandard ports, and redirect chains to prohibited destinations. - Verify that only the exact approved AFAD origin is accepted. ]]>
