Fedora Account System
Red Hat Associate
Red Hat Customer
This flaw was identified by a Red Hat Product Security audit (Glasswing, RHOAIENG-70012, FIND-004). lm-evaluation-harness's EvalHub adapter (main.py) builds the OpenAI-compatible completions URL directly from the JobSpec's model.url field, with no host/scheme allow-list, no RFC1918/link-local/loopback block, and no DNS-rebinding protection: build_lmeval_config() (main.py): base = str(model_spec.url or "").rstrip("/") ... completions_url = f"{base}/v1/completions" ... return ("local-completions", {"model": model_name, "base_url": completions_url, ...}, gen_kwargs) run_benchmark_job() (main.py) resolves the model's bearer credential and exports it into the process environment before the evaluation runs: creds = resolve_model_credentials() if creds.api_key: os.environ["OPENAI_API_KEY"] = creds.api_key The upstream lm_eval "local-completions" backend (lm_eval/models/openai_completions.py, lm_eval/models/api_models.py) reads that same environment variable and attaches it as a Bearer token on every outbound completions request: # openai_completions.py @property def api_key(self): return os.environ.get("OPENAI_API_KEY", "") # api_models.py @cached_property def header(self) -> dict: return {"Authorization": f"Bearer {self.api_key}"} ... response = requests.post(self.base_url, json=..., headers=self.header, verify=self.verify_certificate) job_spec.model.url is a tenant-controlled field of the JobSpec JSON mounted read-only at /meta/job.json (ConfigMap) in the evaluation Job pod. Any authenticated user able to submit an EvalHub evaluation job in their own namespace can set model.url to an arbitrary host, causing the eval pod to POST the resolved bearer credential to that host. The credential is the tenant's own model-auth Secret, mounted in cleartext at /var/run/secrets/model/api-key directly into the runtime container (eval-hub's buildRuntimeContainerVolumesAndMounts, internal/eval_hub/runtimes/k8s/job_builders.go). This allows: - Credential disclosure to an attacker-controlled external listener. - Blind SSRF against internal/link-local endpoints reachable from the evaluation Job pod's network namespace (in-cluster services, cloud metadata endpoints, etc.), gated only by whatever NetworkPolicy applies to that namespace. Verified against red-hat-data-services/lm-evaluation-harness rhoai-3.4 (commit c4a30c07) and red-hat-data-services/eval-hub rhoai-3.4 (commit 4947496): eval-hub's job-building code passes evaluation.Model.URL through to job_spec.model.url unmodified, and mounts the tenant-supplied model-auth Secret directly into the eval container with no rewriting or credential indirection. This is fixed on RHOAI 3.5 by an unrelated architecture change (eval-hub-sdk >= 0.4.x / lm-evaluation-harness commit 614ae2ff, merged 2026-07-16, implementing ADR EH-0004's sidecar credential-injection design): eval-hub's k8s runtime now rewrites job_spec.model.url server-side to always target a co-located sidecar container (only the original request path is preserved; scheme and host are replaced with the sidecar's localhost address), and the credential value the adapter ever holds is an opaque reference token resolvable only inside the sidecar process, which is the only container that mounts the real secret. This scopes the affected range to RHOAI 3.4 only.