Skip to main content

Module ssrf

Module ssrf 

Source
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§

SsrfError
Reason a CIMD client_id URL 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. context is a non-secret label (redacted URL or bare host) used only to build the error message.
is_cgnat
Returns true for the IPv4 carrier-grade NAT range 100.64.0.0/10.
is_ipv4_reserved_broadcast_or_multicast
Returns true for 0.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_reserved covers this but is unstable, so the range check is inlined here), and the limited broadcast address 255.255.255.255.
is_ipv6_ipv4_compatible
Returns true for the deprecated IPv4-compatible IPv6 form (::a.b.c.d, distinct from the IPv4-mapped ::ffff:a.b.c.d form already handled separately via to_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 true for 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_id URL: 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 through check_ip_not_private.