# MLflow: an unauthenticated scorer call makes the server fetch any URL

> MLflow's unauthenticated scorer endpoint built an attacker-named class with attacker-supplied arguments, then sent an outbound request.

- **Severity:** Medium: Real and reproducible, but needs unusual setup, user help or a narrow audience. Plan a fix.
- **Category:** Vulnerability
- **Published by:** MLflow
- **Disclosed:** 2026-10-22
- **CVE:** CVE-2026-115886
- **CVSS:** 6.5
- **Affects:** MLflow, mlflow (PyPI)
- **Research by:** [Adam Jordan](https://github.com/adamyordan)
- **Primary source:** https://github.com/mlflow/mlflow/security/advisories/GHSA-2wqp-q3c6-ccj5
- **Page:** https://theinjection.dev/items/mlflow-scorer-kwargs-ssrf/

MLflow's scorer invoke endpoint built an attacker-named class with unconstrained arguments and no authentication, letting an unauthenticated caller make the tracking server request any host with chosen headers. Fixed in 3.17.0.

## What happened

MLflow maintainers published advisory GHSA-2wqp-q3c6-ccj5 on 22 October 2026 for CVE-2026-115886, a server-side request forgery flaw in the tracking server. Adam Jordan is credited as the reporter. GitHub added the advisory to its database on 23 October, and the fix ships in MLflow 3.17.0.

## How it works

Scorer deserialization reads a class name and constructor arguments from JSON, and the allowlist checks only the import module path, not the class attribute or the arguments. For the trulens scorer, a model URI outside MLflow's native provider registry routes to a LiteLLM fallback branch that forwards raw arguments, including api_base and api_key, into litellm.completion(). An attacker therefore picks the destination host, headers and body of a request the server itself makes. The advisory notes the deserialization runs before any tracking-store lookup, and the route carries error-handling and artifacts-only decorators but no authentication decorator.

## Who is affected

Tracking servers running mlflow from 3.12.0rc0 up to 3.17.0 are exposed, but only where the optional trulens and trulens-providers-litellm packages are installed, which the advisory describes as a documented but not bundled setup. Servers reachable from untrusted networks are the practical concern, because the endpoint needs no authentication. The advisory rates confidentiality and integrity impact Low.

## What to do

Upgrade MLflow to 3.17.0, whose release notes describe the change as rejecting egress-steering kwargs in third-party scorer payloads. Where an upgrade has to wait, the advisory names the optional trulens and trulens-providers-litellm packages as the precondition, so removing them closes the described path.

## Quick facts

- **Affected:** mlflow 3.12.0rc0 up to 3.17.0
- **Fixed in:** MLflow 3.17.0
- **CVE:** CVE-2026-115886
- **CVSS:** 6.5 (v3.1), Moderate
- **Attack type:** Unsafe reflection and SSRF, CWE-470 and CWE-918
- **Precondition:** The optional trulens and trulens-providers-litellm packages installed
- **Found by:** Adam Jordan, reported to the maintainers

## Sources

1. [MLflow Advisory](https://github.com/mlflow/mlflow/security/advisories/GHSA-2wqp-q3c6-ccj5)
2. [GitHub Advisory DB](https://github.com/advisories/GHSA-2wqp-q3c6-ccj5)
3. [MLflow 3.17.0 Release](https://github.com/mlflow/mlflow/releases/tag/v3.17.0)
