T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/idfm.py:251
- Finding
- Caller-Controlled Base URL Can Exfiltrate the IDFM API Key<![CDATA[ ## Vulnerability Details **File Location**: `scripts/idfm.py`, lines 23–50 and 251–272 **Vulnerability Type**: Arbitrary credential-bearing network destination **Risk Level**: High ### Vulnerable Code ```python def _http_get_json(url: str, api_key: str, timeout_s: int = 20) -> dict: req = urllib.request.Request(url) req.add_header("apikey", api_key) req.add_header("accept", "application/json") try: with urllib.request.urlopen(req, timeout=timeout_s) as resp: raw = resp.read().decode("utf-8") return json.loads(raw) except urllib.error.HTTPError as e: body = None try: body = e.read().decode("utf-8", errors="replace") except Exception: pass raise PrimError(f"HTTP {e.code} {e.reason}: {body or ''}".strip()) from e except urllib.error.URLError as e: raise PrimError(f"Network error: {e}") from e class PrimClient: def __init__(self, api_key: str | None = None, base_url: str = BASE_URL): self.api_key = api_key or os.environ.get("IDFM_PRIM_API_KEY") if not self.api_key: raise PrimError("Missing IDFM_PRIM_API_KEY env var") self.base_url = base_url.rstrip("/") def get(self, path: str, params: dict | None = None) -> dict: base = f"{self.base_url}/{path.lstrip('/')}" qs = urllib.parse.urlencode(params or {}, doseq=True) url = f"{base}?{qs}" if qs else base return _http_get_json(url, self.api_key) ``` ```python p.add_argument( "--base-url", default=BASE_URL, help="override PRIM base URL (default: %(default)s)", ) sp = p.add_subparsers(dest="cmd", required=True) p_places = sp.add_parser("places", help="resolve places via /places") p_places.add_argument("query") p_places.add_argument("--count", type=int, default=5) p_j = sp.add_parser("journeys", help="plan a journey via /journeys") p_j.add_argument("--from", dest="from_query", required=True) p_j.add_ar ...[truncated 2907 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove the `--base-url` option from the production command-line interface and always use the fixed `BASE_URL` constant. 2. If destination configurability is required for testing, keep it outside the production CLI or require an explicit development-only configuration. 3. Strictly validate any configurable destination before creating a request: - Require the `https` scheme. - Require the exact hostname `prim.iledefrance-mobilites.fr`. - Reject embedded credentials, fragments, unexpected ports, and deceptive hostname suffixes. - Restrict the path to `/marketplace/v2/navitia`. 4. Ensure the API key is only attached after the final request destination has passed validation. 5. Prevent credential forwarding across redirects to a different scheme, hostname, or port. Either disable redirects or validate every redirect target before resending the authentication header. 6. Add automated tests confirming that HTTP URLs, attacker-controlled domains, localhost, private-network addresses, and cross-host redirects are rejected before any credential-bearing request is sent. 7. Rotate the API key if the affected option has previously been used with an untrusted or unintended destination. ]]>
