A Kerberos concierge who'll dial any phone number a stranger scribbles on a napkin
kdcproxy is a small WSGI app from the latchset project that lets clients tunnel Kerberos over HTTPS to a KDC — commonly fronted by Apache/mod_wsgi on FreeIPA and Red Hat Identity Management servers. When a client asks for a realm that isn't hard-coded in kdcproxy.conf, the default behavior is to resolve _kerberos._tcp.<REALM> via DNS SRV and connect wherever those records point. An unauthenticated attacker who controls a DNS zone can publish SRV records that resolve to 127.0.0.1:22, 169.254.169.254:80, or any internal RFC1918 host and port, and the kdcproxy server will happily open a TCP connection on their behalf. Affected: all python-kdcproxy versions prior to the latchset PR #68 fix; Red Hat has shipped errata (RHSA-2025:21142, :21748, :21820, :21821) for RHEL 8/9/10 and IdM.
The vendor HIGH / 8.6 score comes from AV:N/AC:L/PR:N/UI:N/S:C/C:H — unauth network reach, scope-change, high confidentiality. That vector is technically defensible (it *is* unauth SSRF crossing a trust boundary), but the C:H reading is generous: kdcproxy speaks a Kerberos wire protocol, so exfiltrating arbitrary HTTP responses back to the attacker requires the target service to happen to speak something kdcproxy will forward and echo. In practice you get *blind* SSRF suitable for internal port scanning, topology mapping, and hitting side-effectful GET endpoints — a real bug, but MEDIUM territory once you audit the friction. Blast radius does not reach fleet compromise from this bug alone.
4 steps from start to impact.
Reach an internet-exposed kdcproxy endpoint
/KdcProxy on an IdM/FreeIPA front-end or Apache with mod_proxy_kdcproxy). Shodan/Censys queries for the KDC-PROXY-MESSAGE content-type or IdM banners are the usual discovery path.- kdcproxy WSGI app reachable over the network
- no auth gate in front of
/KdcProxy
- Most IdM deployments are internal-only; kdcproxy on the public internet is uncommon
- Some deployments front kdcproxy with client-cert auth or IP allowlists
python-kdcproxy serviceRegister an attacker-controlled DNS zone with malicious SRV records
evil.example) and publishes _kerberos._tcp.EVIL.EXAMPLE SRV records pointing to target-host:target-port — where target is inside the victim's network (loopback, RFC1918, cloud metadata IP). Tooling: dig, any authoritative DNS provider, or a custom nameserver via dnslib.- Ability to publish authoritative DNS records for a chosen realm name
- kdcproxy config lacks explicit
[REALM]entries for the crafted realm
- Requires attacker to own or delegate a DNS zone — trivial but leaves an audit trail (registrar records, WHOIS)
Send a crafted AS-REQ for the attacker-controlled realm
/KdcProxy naming realm EVIL.EXAMPLE. kdcproxy sees no config entry, falls back to use_dns=true (the default), resolves the SRV record, and connects to the internal target. A one-liner in Python with impacket.krb5.asn1 or the PoC in latchset/kdcproxy PR #68 is enough.use_dnsat default (true)- Egress from kdcproxy host to the chosen internal address:port is not firewalled
- Egress filtering from the kdcproxy host to RFC1918 / loopback varies wildly
- Some hardened builds pin
use_dns=false
POST /KdcProxy with unusual realm; DNS query logs on the kdcproxy host show SRV lookups for third-party zonesEnumerate internal services / hit side-effectful endpoints
169.254.169.254) and unauthenticated internal admin panels are the high-value targets. Full response exfiltration is limited because kdcproxy expects a Kerberos framed reply.- Internal services listening on predictable addresses/ports
- kdcproxy returns distinguishable error signals for open vs closed ports
- No response body echo — impact is blind / semi-blind
- IMDSv2 (AWS) requires PUT with header; SSRF via kdcproxy is GET-style only
The supporting signals.
| In-the-wild exploitation | None observed as of 2026-07-01 — no GreyNoise tags, no vendor IR reports |
|---|---|
| KEV status | Not listed in CISA KEV |
| EPSS | 0.00397 (~0.4%) — low predicted exploitation probability |
| Public PoC | Fix commit + regression tests in latchset/kdcproxy PR #68 demonstrate the primitive; no weaponized exploit in Metasploit/Nuclei yet |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N — unauth network, scope-change, confidentiality-only. C:H is generous given blind-SSRF nature |
| CWE | CWE-918 Server-Side Request Forgery |
| Affected versions | All python-kdcproxy prior to the latchset upstream fix; RHEL packages fixed via RHSA-2025:21142, :21748, :21820, :21821 |
| Fixed versions | Upstream master post-PR #68; RHEL 8 python3-kdcproxy-1.0-4.el8_10, RHEL 9 python3-kdcproxy-1.0-8.el9_6, RHEL 10 current z-stream; Ubuntu tracked, fix landing per USN |
| Exposure population | kdcproxy is bundled with FreeIPA / Red Hat IdM; Shodan shows only low hundreds of internet-exposed IdM front-ends globally — the vast majority are intranet-only |
| Reporter | Reported via Red Hat Product Security; fix authored by jrisc (latchset maintainers) |
| Disclosed | 2025-11-12 |
noisgate verdict.
The single most decisive factor is blast radius: this is blind SSRF that yields internal port scanning and topology mapping, not credential theft, not RCE, not identity takeover — the affected component is an auth *proxy* but the bug does not touch Kerberos ticket handling. Combined with the fact that kdcproxy is rarely exposed to the internet (bundled with IdM/FreeIPA, typically intranet-only), the vendor's 8.6 overstates real-world impact.
Why this verdict
- Blind SSRF, not data exfil: kdcproxy expects a Kerberos-framed reply from the upstream, so arbitrary HTTP response bodies do not round-trip cleanly back to the attacker. The vendor's C:H rating is optimistic.
- Narrow deployment footprint: kdcproxy is an optional component of FreeIPA / Red Hat IdM used to tunnel Kerberos over HTTPS for remote clients. Shodan/Censys populations for internet-facing IdM
/KdcProxyendpoints are in the low hundreds globally. - Attacker must control a DNS zone, which is trivial but leaves registrar and passive-DNS forensic breadcrumbs — raising cost for repeated / targeted use.
- Role multiplier — IdM / FreeIPA front-end: kdcproxy runs on an identity server, which IS a high-value role, but the chain here does NOT end in identity compromise. It ends in internal reconnaissance. Floor is not elevated to HIGH because the bug does not yield ticket forgery, credential access, or lateral movement on its own.
- Trivial config workaround exists: setting
use_dns = falseor defining explicit[REALM]blocks fully mitigates without a code change — many hardened builds already do this.
Why not higher?
HIGH would require either fleet-scale blast radius or a credible path to credential/identity compromise from this primitive alone. Neither holds: the bug is blind SSRF constrained to Kerberos framing, and there is no evidence in the PoC or vendor advisory of ticket-forgery or LDAP-relay pivots. No KEV listing, EPSS <1%.
Why not lower?
LOW would ignore that this IS an unauthenticated pre-auth primitive against an identity-plane component — cloud metadata endpoints and internal admin panels remain plausible targets, and any IdM box exposed to the internet is a real problem. MEDIUM is the honest bucket.
What to do — in priority order.
- Set
use_dns = falsein/etc/kdcproxy.conf— Kills the entire SSRF primitive by disabling SRV fallback. Restart the WSGI worker (systemctl restart httpdon IdM). Deploy within the 365-day noisgate MEDIUM window, but do it this week if your kdcproxy is internet-reachable. - Define explicit
[REALM]entries for every realm you actually serve — Even withuse_dns=true, an explicit realm block short-circuits DNS fallback for that realm. Enumerate every trusted realm and hard-code KDC addresses. - Front
/KdcProxywith an allowlist or mTLS at the reverse proxy — In Apache/nginx in front of kdcproxy, restrict/KdcProxyto known client CIDRs or require client certificates. Prevents opportunistic scan-and-exploit. - Egress-filter the kdcproxy host — The kdcproxy service should only need to reach your legitimate KDCs on 88/tcp and 464/tcp. Block loopback aliases, RFC1918 outside the KDC subnet, and 169.254.169.254 at the host firewall (iptables/nftables) or from a network SG.
- Apply vendor patch — Install RHSA-2025:21142 / :21748 / :21820 / :21821 for RHEL 8/9/10; Ubuntu USN when available. Under noisgate remediation SLA for MEDIUM, complete within 365 days — but bundle into your next monthly IdM maintenance window.
- WAF rules on
/KdcProxy— the request body is opaque ASN.1 (KDC-PROXY-MESSAGE); WAFs cannot parse the realm name without a custom decoder. - Kerberos pre-auth / PKINIT — pre-auth happens at the KDC, not at kdcproxy; the SSRF fires before any auth exchange completes.
- Blocking outbound DNS — the SRV lookup uses the host's normal resolver; you can't stop it without breaking legitimate KDC discovery.
Crowdsourced verification payload.
Run on each IdM / FreeIPA server or any host with python-kdcproxy installed. Requires read access to /etc/kdcproxy.conf and the package manager — typically root. Invoke: sudo bash check-cve-2025-59088.sh.
#!/usr/bin/env bash
# check-cve-2025-59088.sh — detects vulnerable python-kdcproxy configurations
# Exit 0 PATCHED, 1 VULNERABLE, 2 UNKNOWN
set -u
CONF=/etc/kdcproxy.conf
STATE=UNKNOWN
REASON=""
# 1. Is kdcproxy installed?
if command -v rpm >/dev/null 2>&1; then
PKG_VER=$(rpm -q --qf '%{VERSION}-%{RELEASE}\n' python3-kdcproxy 2>/dev/null || rpm -q --qf '%{VERSION}-%{RELEASE}\n' python-kdcproxy 2>/dev/null)
elif command -v dpkg >/dev/null 2>&1; then
PKG_VER=$(dpkg-query -W -f='${Version}\n' python3-kdcproxy 2>/dev/null)
fi
if [ -z "${PKG_VER:-}" ]; then
echo "UNKNOWN: python-kdcproxy not installed"
exit 2
fi
echo "Installed python-kdcproxy: $PKG_VER"
# 2. Config-level mitigation check
if [ -r "$CONF" ]; then
if grep -Eiq '^[[:space:]]*use_dns[[:space:]]*=[[:space:]]*(false|no|0)' "$CONF"; then
STATE=PATCHED
REASON="use_dns explicitly disabled in $CONF"
fi
fi
# 3. Package-level check — RHEL fixed builds
case "$PKG_VER" in
1.0-4.el8_10*|1.0-8.el9_6*|1.0-*.el10*)
STATE=PATCHED
REASON="${REASON:+$REASON; }package version contains vendor fix"
;;
esac
if [ "$STATE" = "PATCHED" ]; then
echo "PATCHED: $REASON"
exit 0
fi
echo "VULNERABLE: python-kdcproxy $PKG_VER without use_dns=false and no fixed package detected"
exit 1
If you remember one thing.
/KdcProxy endpoint is reachable from the internet or from an untrusted network, treat this like a KEV-adjacent finding: add use_dns = false to /etc/kdcproxy.conf and restart httpd today, then schedule the RHSA patch into your next IdM maintenance window. For internal-only IdM (the majority) this is a MEDIUM — noisgate mitigation SLA: no mitigation SLA for MEDIUM, go straight to the noisgate remediation SLA of ≤ 365 days, but bundle it into your next monthly patch cycle so it doesn't rot. Egress-filter kdcproxy hosts to their real KDCs while you're in there — that permanently kills the SSRF class, not just this CVE.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.