Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# proto-file: proto/templated_plugin.proto
# proto-message: TemplatedPlugin

###############
# PLUGIN INFO #
###############

info: {
type: VULN_DETECTION
name: "MLflow_CVE_2026_2635"
author: "sanjaymahajan14"
version: "1.0"
}

finding: {
main_id: {
publisher: "GOOGLE"
value: "CVE-2026-2635"
}
severity: CRITICAL
title: "MLflow Hard-coded Default Credentials Authentication Bypass"
description: "A critical authentication bypass vulnerability exists in MLflow due to hard-coded default credentials in basic_auth.ini. Unauthenticated remote attackers can leverage these default credentials to gain administrative access to MLflow instances, access sensitive models/data, and potentially execute arbitrary code."
recommendation: "Update basic_auth.ini to change default credentials, disable default authentication mechanisms, or upgrade MLflow to a patched version 2.11.0 (or the latest available stable release)."
related_id: {
publisher: "CVE"
value: "CVE-2026-2635"
}
}

config: {}

###########
# ACTIONS #
###########

actions: {
name: "fingerprint_mlflow"
http_request: {
method: GET
uri: "/"
response: {
http_status: 401
expect_any: {
conditions: [
{ body: {} contains: "mlflow" }
]
}
}
}
}

actions: {
name: "probe_default_basic_auth"
http_request: {
method: GET
uri: "/api/2.0/mlflow/users/get?username=admin"
headers: [
# Basic authorization header with default 'admin:password' credentials
{ name: "Authorization" value: "Basic YWRtaW46cGFzc3dvcmQ=" }
]
response: {
http_status: 200
expect_all: {
conditions: [
{ body: {} contains: "\"is_admin\":true" },
{ body: {} contains: "\"username\":\"admin\"" }
]
}
}
}
}

#############
# WORKFLOWS #
#############

workflows: {
actions: [
"fingerprint_mlflow",
"probe_default_basic_auth"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# proto-file: proto/templated_plugin_tests.proto
# proto-message: TemplatedPluginTests

config: {
tested_plugin: "MLflow_CVE_2026_2635"
}

#########
# TESTS #
#########

tests: {
name: "whenVulnerable_returnsTrue"
expect_vulnerability: true

mock_http_server: {
mock_responses: [
# 1. Fingerprint MLflow (401 Unauthorized with basic auth prompt)
{
uri: "/"
status: 401
body_content: "You are not authenticated. Please see https://www.mlflow.org/docs/latest/auth/index.html#authenticating-to-mlflow on how to authenticate."
},
# 2. Probe default admin:password credentials
{
uri: "/api/2.0/mlflow/users/get?username=admin"
status: 200
headers: [
{ name: "Content-Type" value: "application/json" }
]
body_content: "{\"user\":{\"experiment_permissions\":[],\"id\":1,\"is_admin\":true,\"registered_model_permissions\":[],\"username\":\"admin\"}}"
}
]
}
}

tests: {
name: "whenNotVulnerable_returnsFalse"
expect_vulnerability: false

mock_http_server: {
mock_responses: [
# 1. Fingerprint MLflow
{
uri: "/"
status: 401
body_content: "You are not authenticated. Please see https://www.mlflow.org/docs/latest/auth/index.html#authenticating-to-mlflow on how to authenticate."
},
# 2. Basic auth present, but default admin:password fails with 401
{
uri: "/api/2.0/mlflow/users/get?username=admin"
status: 401
headers: [
{ name: "Content-Type" value: "application/json" }
]
body_content: "{\"error_code\":\"UNAUTHORIZED\",\"message\":\"You are not authorized to perform this operation.\"}"
}
]
}
}

tests: {
name: "whenNotMlflow_returnsFalse"
expect_vulnerability: false

mock_http_server: {
mock_responses: [
{
uri: "TSUNAMI_MAGIC_ANY_URI"
status: 200
body_content: "Hello world"
}
]
}
}