CVE-2026-54450 Overview
CVE-2026-54450 affects ToolHive, a utility that simplifies deployment and management of Model Context Protocol (MCP) servers. The networking.IsPrivateIP function in pkg/networking/utilities.go omits the IPv6 NAT64 prefixes 64:ff9b::/96 and 64:ff9b:1::/48. NAT64 addresses that embed private, loopback, or link-local IPv4 targets are therefore classified as public and allowed to pass Server-Side Request Forgery (SSRF) [CWE-918] guards. Attackers can abuse this to probe internal reachability from ToolHive hosts behind a NAT64/DNS64 gateway. The issue is fixed in version 0.29.1.
Critical Impact
An external OAuth client can supply a client_id URL that translates through a NAT64 gateway to internal IPv4 targets such as 169.254.169.254, enabling blind internal TCP/TLS reachability probing.
Affected Products
- ToolHive versions prior to 0.29.1
- Deployments behind a NAT64/DNS64 gateway
- Hosts exposing the CIMD OAuth client metadata fetch path
Discovery Timeline
- 2026-09-15 - CVE-2026-54450 published to NVD
- 2026-09-15 - Last updated in NVD database
- 0.29.1 - Fix released in ToolHive (see GitHub ToolHive Release v0.29.1)
Technical Details for CVE-2026-54450
Vulnerability Analysis
The defective classification lives in networking.IsPrivateIP in pkg/networking/utilities.go. The function checks IPv4 and standard IPv6 private ranges but omits the NAT64 translation prefixes defined by RFC 6052 and RFC 8215. Addresses inside 64:ff9b::/96 and 64:ff9b:1::/48 appear as global-unicast IPv6, so the SSRF guard treats them as public destinations.
Three call sites share the flawed check. protectedDialerControl in pkg/networking/http_client.go and validateHost in pkg/skills/gitresolver/reference.go operate on operator-controlled or user-controlled destinations. CIMDStorageDecorator.GetClient routes an attacker-supplied client_id through FetchClientMetadataDocument in pkg/oauthproto/cimd/fetch.go.
When ToolHive runs behind a NAT64/DNS64 gateway, the gateway rewrites a permitted address such as 64:ff9b:1::a9fe:a9fe to the IPv4 target 169.254.169.254. The attacker gains a blind internal reachability oracle for TCP and TLS endpoints. The CIMD path requires HTTPS and verifies certificates, and it does not reflect response bodies, so metadata credential exfiltration is not established. The webhook client does not use this guard and is not affected.
Root Cause
The IsPrivateIP helper enumerates private CIDR blocks without accounting for NAT64 translation prefixes. An IPv6 address that syntactically belongs to a global-unicast prefix can still route to an embedded internal IPv4 target through a NAT64 gateway.
Attack Vector
An external OAuth client supplies a client_id URL that resolves to a NAT64 address embedding a private IPv4 target. The CIMD fetch path validates the destination with IsPrivateIP, accepts it as public, and issues an HTTPS request. The NAT64 gateway translates the address and forwards the request to the internal target, revealing reachability through timing or TLS handshake outcomes.
// Security patch in pkg/networking/utilities.go (excerpt)
// nat64Prefixes are the NAT64 translation prefixes whose embedded IPv4 address
// lives in the low 32 bits (RFC 6052 §2.2 "/96" embedding). An address inside
// one of these is routed to that IPv4 by a NAT64 gateway, so its true
// reachability is determined by the embedded IPv4, not by the (global-unicast)
// IPv6 form.
// - 64:ff9b::/96 well-known prefix (RFC 6052), always a /96
// - 64:ff9b:1::/96 the /96 sub-prefix of the RFC 8215 local-use 64:ff9b:1::/48
var nat64Prefixes []*net.IPNet
// embeddedIPv4 returns the IPv4 address embedded in the low 32 bits of a NAT64
// address if ip falls inside a NAT64 translation prefix, or nil otherwise.
func embeddedIPv4(ip net.IP) net.IP {
v6 := ip.To16()
if v6 == nil || ip.To4() != nil {
return nil
}
for _, block := range nat64Prefixes {
if block.Contains(ip) {
return net.IPv4(v6[12], v6[13], v6[14], v6[15])
}
}
}
Source: GitHub ToolHive Commit Update
Detection Methods for CVE-2026-54450
Indicators of Compromise
- Outbound HTTPS requests from ToolHive processes to IPv6 destinations inside 64:ff9b::/96 or 64:ff9b:1::/48.
- OAuth client_id URLs registered against ToolHive that resolve to NAT64-prefixed IPv6 addresses.
- CIMD metadata fetch events targeting hosts whose DNS records return NAT64-translated IPv6 answers.
Detection Strategies
- Inspect ToolHive access logs for FetchClientMetadataDocument calls with destinations in the NAT64 prefix ranges.
- Correlate DNS64 responses with subsequent ToolHive egress connections that terminate at internal IPv4 targets after translation.
- Flag any ToolHive HTTP client attempts to reach cloud metadata endpoints such as 169.254.169.254 after NAT64 translation.
Monitoring Recommendations
- Log NAT64 gateway translations that originate from ToolHive hosts and forward them to a centralized data lake.
- Alert on repeated OAuth client registration attempts from unfamiliar external identities targeting the CIMD flow.
- Track ToolHive version inventory to identify hosts still running builds prior to 0.29.1.
How to Mitigate CVE-2026-54450
Immediate Actions Required
- Upgrade ToolHive to version 0.29.1 or later using the release available at GitHub ToolHive Release v0.29.1.
- Audit OAuth client registrations for client_id URLs that resolve to NAT64-prefixed addresses and revoke suspicious entries.
- Restrict outbound network access from ToolHive hosts to only required OAuth issuer endpoints.
Patch Information
The fix adds explicit handling of NAT64 prefixes in pkg/networking/utilities.go. The patched IsPrivateIP extracts the embedded IPv4 address from 64:ff9b::/96 and the /96 sub-prefix of 64:ff9b:1::/48, then evaluates that IPv4 against private ranges. The remainder of 64:ff9b:1::/48 is blocked wholesale to avoid attacker-controlled suffix bytes bypassing the check. See the GitHub Security Advisory GHSA-pph6-vfjv-vpjw and the GitHub ToolHive Commit Update.
Workarounds
- Disable NAT64/DNS64 on networks hosting ToolHive until upgrading is possible.
- Block egress traffic from ToolHive hosts to destinations inside 64:ff9b::/96 and 64:ff9b:1::/48 at the firewall.
- Deny access from ToolHive hosts to cloud metadata services and other link-local IPv4 ranges through host-based filtering.
# Example firewall rules to block NAT64 prefixes for ToolHive hosts
ip6tables -A OUTPUT -d 64:ff9b::/96 -j REJECT
ip6tables -A OUTPUT -d 64:ff9b:1::/48 -j REJECT
iptables -A OUTPUT -d 169.254.169.254 -j REJECT
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

