MLflow Issue Management API BOLA/IDOR Proof-of-Concept
IMPORTANT NOTE: For a comprehensive technical analysis, root cause breakdown, and remediation guidelines, please refer to the Report.md file included in this repository. This README serves primarily as an execution guide for the Proof-of-Concept (PoC).
Overview
This repository demonstrates a High-severity Broken Object Level Authorization (BOLA) / Insecure Direct Object Reference (IDOR) vulnerability in the Issue Management API of MLflow version 3.12.0.
When the basic-auth plugin is enabled, the API fails to validate ownership permissions for Issue objects. This architectural flaw allows any authenticated user to enumerate, read, and modify issues created by other users, bypassing intended project isolation mechanisms.
Vulnerability Summary
- Type: Broken Object Level Authorization (BOLA) / IDOR (CWE-639)
- Library: MLflow (Issue Management API v3)
- Impact: Unauthorized read and modification of confidential project tracking data.
- Root Cause: Absence of authorization logic across routing, service, and database layers; failure to filter SQLAlchemy queries by the
created_byparameter or current user context.
Attack Scenario
In environments relying on MLflow's native authentication:
- Enumeration: An attacker queries the
/api/3.0/mlflow/issues/searchendpoint using a knownexperiment_idto extract deterministicissue_idvalues belonging to the victim. - Unauthorized Read: The attacker sends a
GETrequest to/api/3.0/mlflow/issues/<issue_id>, successfully retrieving the victim's confidential issue metadata. - Unauthorized Modification: The attacker submits a
PATCHrequest to the same endpoint, successfully overwriting the victim's issue data (e.g., name, description, status) without ownership verification.
Repository Structure
mlflow-bola-poc/
βββ Report.md # Full vulnerability analysis, root cause, and remediation
βββ mlflow_bola_poc.py # Core exploit script with API request sequences
βββ auth.ini # Dynamic configuration for MLflow basic-auth isolation
βββ requirements.txt # Dependency specification file
βββ setup_and_run.sh # Automated bash script to initialize venv and run PoC
βββ README.md # This execution guide
Reproduction Steps
1. Execute the Automated Setup Script
Ensure you are in a Unix-like environment (Linux/macOS) with Python 3 installed. Run the bash script to isolate the environment and execute the exploit payload:
chmod +x setup_and_run.sh
bash setup_and_run.sh
2. Observe the Execution Flow
The script dynamically instantiates a local MLflow 3.12.0 server instance on 127.0.0.1:5000 with the basic-auth plugin enabled. It provisions two users: User A (Victim) and User B (Attacker).
The expected terminal output will validate the exploit sequence:
[STEP 8] ATTACK #1: User B reads Alice's issue (V3 API)...
[!] BOLA CONFIRMED: User B reading data from User A!
[STEP 9] ATTACK #2: User B modifies Alice's issue (V3 API)...
[!] BOLA CONFIRMED: User B modifies data from User A!
[STEP 10] ATTACK #3: User B searches all issues (ENUMERATION/V3 API)...
[!] BOLA CONFIRMED: User B listed 1 issue(s) combine issue_id secret of User A!
The script automatically terminates the MLflow server process and purges the temporary SQLite databases to maintain a clean system state.
Security Impact
- Confidentiality: Attackers can extract sensitive operational data, internal architectural discussions, or vulnerability notes logged within the MLflow tracking environment.
- Integrity: Attackers can alter issue statuses, overwrite descriptions, or manipulate metadata, compromising the reliability of project management artifacts within MLflow.
Affected Components
- API Endpoints:
/api/2.0/mlflow/issues/*and/api/3.0/mlflow/issues/* - Controller Layer:
mlflow.server.handlers - Storage Layer:
mlflow.store.tracking.sqlalchemy_store.SqlAlchemyStore - Plugin Integration: MLflow
basic-authplugin.
Mitigation
- Enforce Authorization Context: Implement authentication verification (e.g.,
@require_login) on all issue-related HTTP handlers and inject the user identity into the underlying store methods. - Implement Query-Level Filtering: Modify SQLAlchemy queries to enforce ownership via
.filter(SqlIssue.created_by == current_user_id). - Structural Access Control: Implement a permission matrix linking
user_idtoexperiment_idto validate read/write permissions at the workspace level.
Author
Nguyen Duc Canh (canhnguyen26)