Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
AccessCraft IPv6 transition-form or CGNAT URL embedding internal target
-
DeliverySubmit multimodal Bedrock/Vertex request to Bifrost gateway
-
ExploitisPublicIP classifies forbidden range as public
-
ExecutionFetchAndEncodeURL opens TCP connection to internal host
-
ImpactInternal service response (e.g., IMDS IAM credentials) returned to attacker
Vulnerability Assessment
| Weakness |
CWE
OWASP Top 10:2025
A01:2025 - Broken Access Control
ASVS 5.0
V4 - API and Web Service URL allowlisting, SSRF prevention
MITRE ATT&CK
2 techniques across 2 tactics: Initial Access, Credential Access The technique list with ATT&CK links and the kill-chain view is part of the Basic plan and up. |
| Exploitation Conditions | The attacker must be able to submit multimodal Bedrock or Vertex provider requests to the Bifrost gateway - i.e., the gateway must be configured with at least one of those two providers enabled, and the attacker must have sufficient access to send requests (authentication requirements to the Bifrost API itself are not specified in the advisory; the CVSS PR:N indicates no privilege elevation is required to trigger the fetch). For the highest-impact path (cloud IMDS credential exfiltration via NAT64/6to4), the gateway host must have dual-stack IPv6 networking or NAT64-enabled routing (the default on AWS/GCP IPv6-only subnets), since the NAT64 prefix only routes to |
| Impact | The CVSS 4.0 score of 8.7 (AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H) reflects network-accessible, low-complexity, unauthenticated exploitation. The VC:N/VI:H assignment in the provided vector is debatable - SSRF to IMDS primarily yields credential exfiltration (confidentiality), not integrity; independent assessment places C:H on the subsequent cloud IMDS system. The most severe reachable target is the cloud instance-metadata endpoint (169.254.169.254) via NAT64 or 6to4 wrapping, which can yield IAM/service-account credentials on AWS/GCP IPv6-only or dual-stack deployments. The CGNAT vector (100.64.0.0/10) is live on any deployment whose internal fabric uses RFC 6598 space, including EKS. Critically, the gate-bypass itself is unconditional on all Bifrost deployments - but the downstream impact depends on network topology: NAT64/6to4 IMDS access requires dual-stack or NAT64-enabled routing, and CGNAT access requires the internal network to use that range. No CISA KEV listing exists; exploitation is not confirmed in the wild. A working proof-of-concept is included in the advisory, lowering the barrier to exploitation. The EPSS score is not provided in available data and cannot be independently confirmed. |
| Exploit ScenarioDerived | An attacker with access to a Bifrost deployment's API submits a multimodal chat-completion request to the Vertex provider, placing |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv2 – Aug 28, 2026
SSRF in the Bifrost AI gateway's multimodal URL-fetch path permits any client that can submit a Bedrock or Vertex provider request to reach internal network services - including cloud instance-metadata endpoints - by supplying IPv6 transition-form addresses (6to4, NAT64) or CGNAT addresses that the isPublicIP deny-list in core/providers/utils/fetch.go incorrectly classifies as routable public IPs. All releases of the github.com/maximhq/bifrost/core Go module prior to v1.5.17 are affected, confirmed on dev HEAD f415c14 (core/version 1.5.15). Publicly available exploit code exists in the GHSA advisory as a runnable Go test; no CISA KEV listing at time of analysis.
Earlier versions of this analysis (1)
Server-side request forgery in maximhq/bifrost's AI gateway allows any API client to reach internal network services by supplying specially crafted IPv6 transition addresses in multimodal request URLs. The isPublicIP deny-list in core/providers/utils/fetch.go fails to block CGNAT space (100.64.0.0/10), IPv6 6to4 (2002::/16), NAT64 well-known (64:ff9b::/96) and local-use (64:ff9b:1::/48) prefixes, and deprecated site-local (fec0::/10) - meaning an attacker can encode 169.254.169.254 as 2002:a9fe:a9fe:: or 64:ff9b::a9fe:a9fe to reach the cloud instance-metadata endpoint and harvest cloud credentials. No public exploit identified at time of analysis, though a detailed proof-of-concept is included in the GHSA advisory.
RemediationAI
Vendor-released patch: core/v1.5.17, available at https://github.com/maximhq/bifrost/releases/tag/core/v1.5.17. The fix (commit 54ec431fc5255ff42c36420d88549477e0b33d89, PR #4092) adds an explicit CGNAT prefix check (100.64.0.0/10), an embeddedIPv4 extractor that unwraps 6to4 and both NAT64 prefixes before re-running all deny-list checks, and an explicit fec0::/10 site-local rejection. Upgrading is the only complete fix. If immediate upgrade is not possible, operators can apply one of the following compensating controls with trade-offs: (1) Block multimodal URL-fetch requests at the ingress layer by stripping or rejecting FileURL and image URL fields in Bedrock and Vertex request bodies - this disables multimodal document/image fetching entirely; (2) Restrict outbound connections from the Bifrost process to confirmed-public CIDRs via an egress firewall or network policy, explicitly denying 100.64.0.0/10, 2002::/16, 64:ff9b::/96, 64:ff9b:1::/48, and fec0::/10 - this does not modify Bifrost behavior but limits reachable targets if the network supports it. Neither workaround is equivalent to the patch.
Affected VersionsENISA
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 2 packages in go, euvd
Checking this CVE against your own stacks and servers is part of the Basic plan and up.
Technical ContextAI · show details
Bifrost is an open-source AI LLM gateway (Go module github.com/maximhq/bifrost/core) that proxies multimodal chat-completion requests to cloud providers including AWS Bedrock and Google Vertex AI. The FetchAndEncodeURL function in core/providers/utils/fetch.go fetches remote image and document URLs supplied in multimodal content blocks, guarded by isPublicIP. The flaw is that Go's netip.Addr.IsPrivate() covers only RFC 1918 (10/8, 172.16/12, 192.168/16) and RFC 4193 ULA (fc00::/7) - it does not cover CGNAT RFC 6598 (100.64.0.0/10), common in EKS pod CIDR and Kubernetes overlay networks. Go's Unmap() collapses only ::ffff:0:0/96 IPv4-mapped addresses; it does not reduce 6to4 (2002::/16, where bytes 2-5 embed the IPv4) or NAT64 (64:ff9b::/96 well-known, 64:ff9b:1::/48 local-use) IPv6 forms. This means 2002:a9fe:a9fe:: and 64:ff9b::a9fe:a9fe - both encoding 169.254.169.254 - pass all checks and the gateway opens a real TCP connection. Deprecated IPv6 site-local fec0::/10 (RFC 3879) is also unmatched. CWE-918 (Server-Side Request Forgery). The exploit surface is limited to the multimodal paths: core/providers/bedrock/utils.go:1073,1187 and core/providers/vertex/vertex.go:402.
Know when Kubernetes gets its next vulnerability
- Watch products and get an email when something new is published
- Check this CVE against your own stack and servers
- Exploit and PoC references, threat intelligence from 22 sources
No credit card · 7-day full trial
Severity by source
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N
Scope changes because the gateway reaches internal systems on the attacker's behalf; C:H reflects IMDS credential exfiltration; I:L covers incidental internal API calls; no availability impact.
Primary rating from Vendor (https://github.com/maximhq/bifrost).
CVSS VectorVendor: https://github.com/maximhq/bifrost
Lifecycle Timeline
3DescriptionCVE.org
Summary
isPublicIP in core/providers/utils/fetch.go - the SSRF deny-list that gates FetchAndEncodeURL - does not reject several routable address ranges that map onto internal infrastructure. Carrier-Grade NAT (100.64.0.0/10, RFC 6598), IPv6 6to4 (2002::/16), NAT64 (64:ff9b::/96 and 64:ff9b:1::/48), and deprecated IPv6 site-local (fec0::/10) are all classified as public and permitted. An attacker who controls a multimodal image/document URL in a Bedrock or Vertex request body can drive the gateway to fetch internal services it should not reach - including the cloud instance-metadata endpoint via the 6to4 / NAT64 embeddings of 169.254.169.254.
The rest of the fetch hardening is correct and is not part of this report: the dial-time LookupIP + pin to ips[0] closes the DNS-rebinding TOCTOU, CheckRedirect re-validates redirect targets, the scheme gate, the 25 MiB cap, and the 20 s timeout all work. This is purely a residual IP-classification gap in isPublicIP.
Affected component
- File:
core/providers/utils/fetch.go, functionisPublicIP(lines 107-118), reached only throughFetchAndEncodeURL(line 28). - Go module:
github.com/maximhq/bifrost/core - Version: confirmed on the current
devHEADf415c144678bd4b411d74a1c1f85f18652833224(core/version=1.5.15).
Vulnerable code
func isPublicIP(ip net.IP) bool {
addr, ok := netip.AddrFromSlice(ip)
if !ok {
return false
}
addr = addr.Unmap()
if addr.IsLoopback() || addr.IsPrivate() || addr.IsLinkLocalUnicast() || addr.IsLinkLocalMulticast() ||
addr.IsMulticast() || addr.IsUnspecified() || addr.IsInterfaceLocalMulticast() {
return false
}
return true
}addr.IsPrivate() covers only RFC 1918 + RFC 4193 (fc00::/7); it does not cover CGNAT 100.64.0.0/10. addr.Unmap() only collapses the ::ffff:0:0/96 IPv4-mapped form, so 6to4 (2002::/16) and NAT64 (64:ff9b::/96, 64:ff9b:1::/48) IPv6 representations of internal/link-local IPv4 are never reduced to their embedded address and slip past every check. fec0::/10 (deprecated IPv6 site-local) is likewise not matched by any of the helpers used.
Attack surface / who can trigger it
FetchAndEncodeURL is invoked from the multimodal request-handling path of two providers:
core/providers/bedrock/utils.go:1073(documentblock.File.FileURL),:1187(image URL viaconvertImageToBedrockSource)core/providers/vertex/vertex.go:402(documentblock.File.FileURL)
These URLs come straight from the client's chat-completion request body (a remote image/document URL in a multimodal content block). SanitizeImageURL (core/schemas/utils.go:180) only checks the scheme and a non-empty host - it performs no address filtering - so isPublicIP is the sole network guard, and it is always on (no opt-out flag). On a multi-tenant or shared gateway deployment, any client able to send a request can choose the fetch target.
Impact
Server-side request forgery from the gateway into internal address space that the deny-list intends to block:
- CGNAT
100.64.0.0/10- reachable anywhere the internal fabric uses RFC 6598 space (common in Kubernetes overlay networks and cloud NAT fabrics). Live on any such host with no extra preconditions. - 6to4
2002:a9fe:a9fe::and NAT6464:ff9b::a9fe:a9fe- both embed169.254.169.254, the cloud instance-metadata endpoint. On a dual-stack or NAT64-enabled host (the default on AWS/GCP IPv6-only subnets) these reach IMDS even though the direct169.254.169.254and::ffff:169.254.169.254forms are correctly blocked. fec0::/10- deprecated site-local, still routed on some networks.
CWE-918 (Server-Side Request Forgery). Self-discovered while reviewing IP-classification deny-lists; the missing dimensions match the classes accepted as HIGH in the canonical references below.
Proof of concept
A test placed in-package (core/providers/utils/) drives the real FetchAndEncodeURL - real http.Client, real Transport.DialContext, real isPublicIP - and classifies each target by whether isPublicIP let it past the gate. A blocked fetch to non-public address error means the gate rejected it before any dial (safe); any other outcome means the gate permitted the dial to a forbidden range (SSRF reachable).
package utils
import (
"context"
"fmt"
"strings"
"testing"
"time"
)
func TestSSRFGateDecision(t *testing.T) {
cases := []struct{ name, url string }{
{"CGNAT-100.64", "http://100.64.1.1:9/"},
{"CGNAT-100.127", "http://100.127.255.254:9/"},
{"6to4-IMDS", "http://[2002:a9fe:a9fe::]:9/"},
{"NAT64-IMDS", "http://[64:ff9b::a9fe:a9fe]:9/"},
{"NAT64-local-IMDS", "http://[64:ff9b:1::a9fe:a9fe]:9/"},
{"sitelocal-fec0", "http://[fec0::1]:9/"},
// controls (must be rejected at the gate):
{"CONTROL-direct-IMDS", "http://169.254.169.254:9/"},
{"CONTROL-RFC1918", "http://10.0.0.1:9/"},
{"CONTROL-loopback", "http://127.0.0.1:9/"},
{"CONTROL-mapped-IMDS", "http://[::ffff:169.254.169.254]:9/"},
}
for _, c := range cases {
ctx, cancel := context.WithTimeout(context.Background(), 4*time.Second)
_, _, err := FetchAndEncodeURL(ctx, c.url)
cancel()
gateBlocked := err != nil && strings.Contains(err.Error(), "blocked fetch to non-public address")
fmt.Printf("%-22s gateBlock=%-6v %v\n", c.name, gateBlocked, err)
}
}Verbatim output (go test ./providers/utils/ -run TestSSRFGateDecision -v against HEAD f415c14, Go 1.26.1):
=== bifrost FetchAndEncodeURL SSRF gate decision (REAL code path) ===
target gateBlock verbatim error / outcome
----------------------------------------------------------------------------------------------------
CGNAT-100.64 false failed to fetch from "http://100.64.1.1:9/": Get "http://100.64.1.1:9/": context deadline exceeded
CGNAT-100.127 false failed to fetch from "http://100.127.255.254:9/": Get "http://100.127.255.254:9/": context deadline exceeded
6to4-IMDS false failed to fetch from "http://[2002:a9fe:a9fe::]:9/": Get "http://[2002:a9fe:a9fe::]:9/": EOF
NAT64-IMDS false failed to fetch from "http://[64:ff9b::a9fe:a9fe]:9/": Get "http://[64:ff9b::a9fe:a9fe]:9/": context deadline exceeded
NAT64-local-IMDS false failed to fetch from "http://[64:ff9b:1::a9fe:a9fe]:9/": Get "http://[64:ff9b:1::a9fe:a9fe]:9/": context deadline exceeded
sitelocal-fec0 false failed to fetch from "http://[fec0::1]:9/": Get "http://[fec0::1]:9/": EOF
CONTROL-direct-IMDS true failed to fetch from "http://169.254.169.254:9/": Get "http://169.254.169.254:9/": blocked fetch to non-public address 169.254.169.254
CONTROL-RFC1918 true failed to fetch from "http://10.0.0.1:9/": Get "http://10.0.0.1:9/": blocked fetch to non-public address 10.0.0.1
CONTROL-loopback true failed to fetch from "http://127.0.0.1:9/": Get "http://127.0.0.1:9/": blocked fetch to non-public address 127.0.0.1
CONTROL-mapped-IMDS true failed to fetch from "http://[::ffff:169.254.169.254]:9/": Get "http://[::ffff:169.254.169.254]:9/": blocked fetch to non-public address 169.254.169.254Reading the result: every control (direct IMDS, RFC 1918, loopback, IPv4-mapped IMDS) is rejected at the gate with blocked fetch to non-public address and no socket is ever opened. Every CGNAT / 6to4 / NAT64 / site-local target instead passes isPublicIP and proceeds to the network dial - observed as context deadline exceeded or EOF (a real connection attempt), never blocked fetch to non-public address. The blocked vs dial-attempted split isolates the isPublicIP classification defect precisely.
A standalone re-check of the verbatim isPublicIP body confirms the classification directly (Go 1.26.1):
100.64.0.1 isPublicIP=true (CGNAT - should be blocked)
100.127.255.254 isPublicIP=true (CGNAT)
2002:a9fe:a9fe:: isPublicIP=true (6to4 -> 169.254.169.254)
64:ff9b::a9fe:a9fe isPublicIP=true (NAT64 -> 169.254.169.254)
64:ff9b:1::a9fe:a9fe isPublicIP=true (NAT64 local-use -> 169.254.169.254)
fec0::1 isPublicIP=true (deprecated site-local)
169.254.169.254 isPublicIP=false (direct IMDS - correctly blocked, control)
::ffff:169.254.169.254 isPublicIP=false (IPv4-mapped - correctly blocked, control)
8.8.8.8 isPublicIP=true (public - correctly allowed, control)Honest scope note
The test host used for verification has no CGNAT/NAT64 routing that returns to a local recorder, so I did not capture live instance-metadata bytes here - the connection lands on the upstream NAT or times out. The 6to4/NAT64 vectors require a dual-stack or NAT64-enabled host to reach IMDS, and the CGNAT vector requires the deployment's internal network to use 100.64.0.0/10. These are the same routing preconditions the references below were accepted under. The defect demonstrated above is unconditional: isPublicIP permits the forbidden ranges on every host.
References (canonical dimension precedents)
- CVE-2026-45741 / GHSA-86m8-88fq-xfxp - Gotenberg
IsPublicIPIPv6 6to4 / NAT64 / site-local bypass; same Gonetip+Unmapgap. - GHSA-5jh9-2h63-pw4q - CC-Tweaked NAT64 (
64:ff9b::/96) bypass; their fix addsisCarrierGradeNatAddress(CGNAT) + NAT64 handling.
Suggested fix
In isPublicIP, after Unmap():
- Reject CGNAT:
100.64.0.0/10for IPv4 (and the::ffff:100.64.0.0/106mapped form is already handled byUnmap). - For IPv6, extract any embedded IPv4 and re-run the classification on it: 6to4 (
2002::/16-> bytes 2-5), NAT64 well-known (64:ff9b::/96) and local-use (64:ff9b:1::/48) -> low 32 bits. Then apply the same loopback/private/link-local/CGNAT checks to the extracted IPv4. - Reject deprecated site-local
fec0::/10.
Articles & Coverage 1
Technical POC Analysis
CWE-918.
Full technical POC analysis - root cause, step-by-step exploitation and patch breakdown - is part of the Pro and Business plans.
Executive ViewAI
The Bifrost AI gateway (versions prior to v1.5.17) has a server-side request forgery vulnerability with publicly available exploit code, allowing attackers with API access to reach internal network services and cloud metadata endpoints. This exposure risks unauthorized access to sensitive cloud infrastructure and could enable data exfiltration and privilege escalation. Organizations using Bifrost for Bedrock or Vertex AI integrations require immediate patching.
Vendor-released patch: v1.5.17
Threat Intelligence Overview
How this decision was reached
The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.
What every action level means
SSVC AssessmentENISA
Priority Score
Attack Technique
Server-Side Request Forgery exploits applications that fetch remote resources based on user-supplied URLs.
More in Kubernetes
View allA critical vulnerability in Kubernetes ingress-nginx controller allows unauthenticated attackers with pod network access
Credential-harvesting malware compromised 84 versions of 42 TanStack npm packages on 2026-05-11 via chained GitHub Actio
Kubernetes ingress-nginx contains a configuration injection vulnerability via the mirror-target and mirror-host Ingress
A security issue was discovered in ingress-nginx https://github.com/kubernetes/ingress-nginx where the `auth-url` Ingres
A security issue was discovered in ingress-nginx https://github.com/kubernetes/ingress-nginx where the `auth-tls-match-c
Kubernetes API server in all versions allow an attacker who is able to create a ClusterIP service and set the spec.exter
A security issue was discovered in Kubernetes where a user that can create pods on Windows nodes may be able to escalate
Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes. Rated critical severity (CVSS 9.9), this vulne
Unauthenticated remote attackers can trigger complete database overwrites, server-side file reads, and SSRF attacks agai
The Kubernetes integration in GitLab Enterprise Edition 11.x before 11.2.8, 11.3.x before 11.3.9, and 11.4.x before 11.4
Fluentd configuration injection in the kube-logging Logging operator before 6.6.0 allows a namespace-scoped user who can
Authenticated Typebot users can abuse the webhook block (HTTP Request component) in versions prior to 3.13.1 to issue ar
EUVD-2026-67860
GHSA-w98g-5w9p-p3rc
NVD
CVE.org
EPSS
Vulnrichment
Exploit-DB