T09 · Insecure Skill Coding Practices
- Location
track.py:10- Finding
Unrestricted API Base URL Exposes Credentials and Shipment Data
- Content
View full analysis
str: return os.getenv("TRACK123_API_BASE", "https://api.track123.com/gateway/open-api/tk/v2") def get_api_secret() -> str: secret = os.getenv("TRACK123_API_SECRET") if not secret: raise RuntimeError("TRACK123_API_SECRET not set") return secret def api_headers() -> Dict[str, str]: return { "Track123-Api-Secret": get_api_secret(), # Track123 Header[web:35] "accept": "application/json", "content-type": "application/json", } def query_track123(tracking_number: str, postal_code: str | None) -> Dict[str, Any]: """ Track123 /track/query – auto-detect mit leerem courierCode.[web:35] """ url = f"{get_api_base()}/track/query" payload = { "trackNos": [tracking_number], "orderNos": [""], "queryPageSize": 1, } if postal_code: payload["postalCode"] = postal_code # Für Filterung/Erweiterung[web:35] resp = requests.post(url, headers=api_headers(), json=payload) ``` ### Technical Analysis The `TRACK123_API_BASE` environment variable is accepted without validating its URL scheme, hostname, port, or resolved destination. The application then unconditionally attaches the `TRACK123_API_SECRET` header and submits the user's tracking number and optional postal code to that destination. An attacker who can influence the process environment or deployment configuration can set the base URL to an attacker-controlled server. The code also accepts plaintext HTTP URLs, allowing the API secret and shipment data to be transmitted without transport encryption. Because `requests.post()` follows redirects by default, redirect handling should also be constrained so the custom secret header cannot re ...[truncated 1849 chars]- Remediation
View remediation
str: base = os.getenv( "TRACK123_API_BASE", "https://api.track123.com/gateway/open-api/tk/v2", ).rstrip("/") parsed = urlparse(base) if ( parsed.scheme != "https" or parsed.ho ...[truncated 385 chars]
