Expand description
SSRF preflight guard for CIMD client_id URL fetches.
This is a static preflight — it does not perform DNS resolution. It
rejects non-https schemes, userinfo, query/fragment components, a
missing or root-only path, private-TLD-suffixed hostnames, textual
loopback hostnames, and IP-literal hosts that fall in a private/
loopback/link-local/CGNAT/ULA/transition-mechanism/multicast range.
Callers that resolve a domain name to an IP address MUST additionally
run each resolved address through check_ip_not_private before
connecting, and MUST re-validate the actual TCP peer post-connect (see
cimd::document::resolve_and_validate_address and
cimd::document::fetch_document_at) — this module alone does not close
the DNS-rebinding/proxy-interception gap by itself.
Adapted (not imported — this crate has no path dependency on the
sibling lab repo) from the equivalent guard in
labby-primitives::ssrf and its caller,
labby-apis::acp_registry::installer, which additionally documents and
implements post-connect peer re-validation as “the load-bearing line of
the SSRF TOCTOU / DNS-rebinding defense” — that additional layer is
implemented in cimd::document, not here (this module only covers the
static/pre-DNS portion of the reference’s rigor).
Enums§
- Ssrf
Error - Reason a CIMD
client_idURL was rejected.
Constants§
- PRIVATE_
TLD_ SUFFIXES - Private-DNS suffix denylist applied to non-IP hosts. Belt-and-suspenders on top of the resolved-IP checks (an internal name might resolve through split-horizon DNS to a public-looking record at validation time).
Functions§
- check_
ip_ not_ private - Reject an IP that targets private, loopback, link-local, CGNAT, ULA,
IPv4-mapped-private, IPv4-compatible, transition-mechanism, reserved,
multicast, or broadcast space.
contextis a non-secret label (redacted URL or bare host) used only to build the error message. - is_
cgnat - Returns
truefor the IPv4 carrier-grade NAT range100.64.0.0/10. - is_
ipv4_ reserved_ broadcast_ or_ multicast - Returns
truefor0.0.0.0/8(“this network”, broader than the single unspecified address), IPv4 multicast (224.0.0.0/4), Class E reserved space (240.0.0.0/4, RFC 1112 §4 —Ipv4Addr::is_reservedcovers this but is unstable, so the range check is inlined here), and the limited broadcast address255.255.255.255. - is_
ipv6_ ipv4_ compatible - Returns
truefor the deprecated IPv4-compatible IPv6 form (::a.b.c.d, distinct from the IPv4-mapped::ffff:a.b.c.dform already handled separately viato_ipv4_mapped()). Some stacks still route this form; treat any non-loopback, non-unspecified address here as embedding a target IPv4 address this guard has not yet validated. - is_
ipv6_ transition_ mechanism - Returns
truefor IPv6 transition-mechanism prefixes that embed an IPv4 address reachable through the mechanism — NAT64 (64:ff9b::/96), 6to4 (2002::/16), and Teredo (2001::/32). These are more credible SSRF bypasses than IPv6 documentation ranges and are blocked wholesale (not selectively unwrapped) since this is a conservative preflight for an OAuth Authorization Server fetching an attacker-supplied URL, not a general-purpose network client that needs transition-mechanism support. - validate_
url_ shape - Parse and statically validate a CIMD
client_idURL: require https, forbid userinfo/query/fragment, require a non-root path component, require a host, and reject the private-TLD/loopback host denylist. If the host is an IP literal it is additionally run throughcheck_ip_not_private.