T09 · Insecure Skill Coding Practices
- Location
scripts/ry-data.py:62- Finding
API Key Can Be Transmitted to an Arbitrary Configured Endpoint
- Content
View full analysis
str: url = os.environ.get("RY_DATA_BASE_URL", "").strip() if not url: cfg = load_config() url = (cfg.get("base_url") or "").strip() return url or DEFAULT_BASE_URL ``` ```python def api_request(method: str, path: str, body=None, query: dict | None = None) -> dict: """Send HTTP request to API. Returns parsed JSON response.""" base = get_base_url() url = f"{base}{path}" if query: url += "?" + urllib.parse.urlencode({k: v for k, v in query.items() if v is not None}) headers = { "Content-Type": "application/json", "Accept": "application/json", } secret_key = get_secret_key() if secret_key: headers["X-API-Key"] = secret_key data = json.dumps(body).encode("utf-8") if body else None req = urllib.request.Request(url, data=data, headers=headers, method=method) try: with urllib.request.urlopen(req, timeout=30) as resp: result = json.loads(resp.read().decode("utf-8")) ``` ### Technical Analysis The API base URL can be overridden through either the `RY_DATA_BASE_URL` environment variable or the `base_url` field in `scripts/config.json`. The value is used without validating its scheme, hostname, port, or ownership. Every API request then automatically attaches the credential from `RY_DATA_SECRET_KEY` or `config.json` as the `X-API-Key` header. Consequently, the credential is not restricted to the declared service at `https://ry-api.dso100.com`. It can be sent to any HTTP or HTTPS server selected through configuration. Allowing a configurable service endpoint can be legitimate, but forwarding the production credential to an unrestricted destination exceeds the minimum privileges required for the declared functionality. Plain H ...[truncated 1216 chars]- Remediation
View remediation
