
Milvus 认证安全检测脚本:CVE-2025-64513 (sourceid后门) / CVE-2026-26190 (/expr弱token) / 内部端口53100
Milvus authentication security audit script. Detects three authentication flaws:
| Flaw | CVE | Affected versions | Detection method |
|---|---|---|---|
| sourceid backdoor auth bypass | CVE-2025-64513 | < 2.4.24 / < 2.5.21 / < 2.6.5 | gRPC ListDatabases + sourceid injection |
| Management port /expr weak token | CVE-2026-26190 | < 2.5.27 / < 2.6.10 | HTTP /expr?code=1%2B1&auth=by-dev (code parameter must be URL-encoded) |
| Internal port rootcoord 53100 no auth | — | < 2.6.10 (no longer listening since 2.6.10) | Direct gRPC connection to RootCoordService |
# proxy-level detection (sourceid backdoor + /expr weak token)
python3 milvus-auth-audit.py --host 127.0.0.1 --port 19530 --mgmt-port 9091
# full detection (including internal port, requires reachability within the container network)
python3 milvus-auth-audit.py --host <container-IP> --port 19530 --mgmt-port 9091 --internal-port 53100
Arguments:
--host: Milvus proxy address--port: proxy gRPC port (default: 19530)--mgmt-port: management port (default: 9091, where /expr is served)--internal-port: internal port (rootcoord defaults to 53100; pass 0 to skip)--cve-check: print CVE affected-version detailspip install grpcio protobuf
gRPC calls require Python code generated from the proto definitions (milvus_pb2_grpc.py, root_coord_pb2_grpc.py, etc.), placed in the proto/ subdirectory alongside the script. To generate:
# 1. clone the milvus-proto repo
git clone https://github.com/milvus-io/milvus-proto.git
# 2. clone the milvus source (internal protos: root_coord.proto / internal.proto / proxy.proto, etc.)
git clone https://github.com/milvus-io/milvus.git
# 3. generate (milvus internal protos live under milvus/pkg/proto/)
pip install grpcio-tools
python3 -m grpc_tools.protoc -I milvus-proto/proto -I milvus/pkg/proto \
--python_out=proto --grpc_python_out=proto \
milvus-proto/proto/milvus.proto milvus/pkg/proto/root_coord.proto \
milvus/pkg/proto/internal.proto milvus/pkg/proto/proxy.proto
=== 2.6.4 ===
[*] target: 172.22.0.4:19530 management port: 9091
[check] auth status: enabled (authorizationEnabled=true)
[verify] sourceid backdoor bypasses authentication, databases=['default'] -> HIT
[verify] /expr arbitrary expression execution (auth=by-dev) -> HIT
[exploit] internal port unauthenticated, databases=['default'] -> HIT
[!] found 3 exploitable authentication flaws
=== 2.6.5 ===
[check] auth status: enabled (authorizationEnabled=true)
[verify] sourceid rejected -> SAFE
[verify] /expr arbitrary expression execution (auth=by-dev) -> HIT
[exploit] internal port unauthenticated, databases=['default'] -> HIT
[!] found 2 exploitable authentication flaws
=== 2.6.10 ===
[check] auth status: enabled (authorizationEnabled=true)
[verify] sourceid rejected -> SAFE
[verify] /expr disabled by default -> SAFE
[exploit] port unreachable -> SAFE
[+] no authentication flaws found
validSourceID() in internal/proxy/authentication_interceptor.go checks the sourceId header; when its base64-decoded value equals @@milvus-member@@, the entire authentication branch is skipped. This is an internal component trust mechanism (PerRPCCredentials in grpcclient/auth.go), but there is no source validation, so it can be forged externally. Full exploit chain: sourceid + authorization=base64("root:假密码") = full admin (proxy skips validation and forwards the fake identity unchanged)./expr debug endpoint on management port 9091 derives its auth token from etcd.rootPath (default by-dev), which is completely predictable, allowing arbitrary expr-lang expressions to be executed. Since 2.6.10, it is controlled by common.security.exprEnabled and disabled by default.AuthenticationInterceptor is only registered on the proxy (19530); the rootcoord internal gRPC server (53100) has no authentication. An unauthenticated direct connection within the container network is enough for full admin. Since 2.6.10, this port is no longer listening.For security testing in authorized environments only. Do not use against unauthorized systems.