The Password Was “password1234”. It Was Shipped That Way on Purpose. | by Sreejith Gopinath | Jun, 2026 | MediumSitemapOpen in appSign up<br>Sign in
Medium Logo
Get app<br>Write
Search
Sign up<br>Sign in
The Password Was “password1234”. It Was Shipped That Way on Purpose.
Sreejith Gopinath
10 min read·<br>Just now
Listen
Share
A static analysis of MLflow found nine security findings. What happened when I reported them is the more interesting story.<br>Author: Sreejith Gopinath<br>Published: May 27, 2026<br>Methodology: Static source code analysis<br>Disclosure: Filed via GitHub Security Advisories, April 27–30, 2026. Vendor engaged May 8, 2026. All findings resolved same day.
Background<br>MLflow is an open-source platform for managing the machine learning lifecycle, originally created by Databricks and donated to the Linux Foundation in 2020. It is widely deployed in data science teams, research institutions, and production ML infrastructure, including systems that store credentials, model artifacts, and API keys for connected LLM providers.<br>In late April 2026 I conducted a static source code analysis of the MLflow codebase and identified nine security findings spanning hardcoded credentials, OS command injection, code injection, missing authorization, and cryptographic misconfiguration. I filed all nine via GitHub Security Advisories on April 27–30, 2026.<br>For ten days, nothing happened.<br>Then one escalation email to Databricks security changed everything.
The Disclosure Timeline<br>April 27–30, 2026: Nine GitHub Security Advisories filed against mlflow/mlflow. Maintainers auto-added as collaborators. No engagement.<br>May 4, 2026: GitHub Security Lab confirmed they cannot issue CVEs without maintainer involvement and directed me to MITRE. Nine CVE IDs requested from MITRE (case MCID15746224).<br>May 8, 2026, 10:27am: One email sent to bugbounty@databricks.com referencing all nine advisories and the MITRE submission. AK(pseudonym) at Databricks responded within the hour, flagging the advisories to the maintainer team.<br>May 8, 2026, 8:15pm: B-Step62 (YW, Databricks) began reviewing advisories.<br>May 8, 2026, 8:41pm: All nine advisories closed. Five pull requests opened. All co-authored with or credited to @sreelim.<br>Twenty-six minutes from first response to complete resolution.
The Findings<br>Finding 1 — Critical: Hardcoded Default Admin Credentials<br>GHSA: GHSA-7v72-hrvh-8fjh | CWE: CWE-798 | CVSS 3.1: 9.8<br>Description<br>MLflow ships mlflow/server/auth/basic_auth.ini with hardcoded administrator credentials publicly visible in the source repository:<br>[mlflow]<br>admin_username = admin<br>admin_password = password1234At startup, mlflow/server/auth/__init__.py line 3919 calls create_admin_user(auth_config.admin_username, auth_config.admin_password) verbatim with no check for whether the default password remains unchanged and no warning emitted.<br>Reproduction<br>mlflow server --app-name basic-auth --host 0.0.0.0 --port 5000curl -u admin:password1234 http://localhost:5000/api/2.0/mlflow/experiments/listcurl -u admin:password1234 \<br>-X POST http://localhost:5000/api/2.0/mlflow/users/create \<br>-H "Content-Type: application/json" \<br>-d '{"username": "attacker", "password": "owned", "is_admin": true}'Vendor Response<br>“We don’t consider this a remote vulnerability. To be exposed, an operator must enable basic auth and skip the documented admin_password override. The CVSS 9.8 with PR:N doesn’t apply here, since the principal is the deploying admin, not an external attacker. That said, the warning gap is a fair point. We’ll land a startup check that warns when the default password is in use.”<br>Assessment<br>The PR:N argument conflates operator prerequisites with attacker prerequisites. Once basic auth is enabled with default credentials, exploitation requires no attacker privileges — that is definitionally PR:N. The operator’s configuration mistake is a separate dimension from the attacker’s required privilege level.<br>PR #23182 adds a startup warning that fires when admin_password == "password1234" and is marked as a bug fix for the next release. The fix is the right remediation even if we disagree on CVE classification. Notably, the commit is co-authored by @sreelim.<br>PR #23182: https://github.com/mlflow/mlflow/pull/23182 Status: Merged in MLflow 3.12.0. Co-authored by @sreelim.
Finding 2 — High: Shell Injection via -P Parameter Keys<br>GHSA: GHSA-w8c3-p3fc-fv5g | CWE: CWE-78<br>Description<br>MLflow’s mlflow run -P flag interpolates parameter key names unescaped into a bash -c invocation. _sanitize_param_dict in mlflow/projects/_project_spec.py:305 quotes values but not keys. compute_command then joins these into a shell string passed to bash -c.<br>Vendor Response<br>“The principal supplying -P key=value is the user invoking mlflow run from their own shell — they already control the host process. There’s no privilege boundary crossed. The quoting fix is trivial and worth landing as code quality. We’ll apply shlex.quote to keys in a regular PR. Crediting you in the...