Coverage for src/local_deep_research/security/ip_ranges.py: 100%
3 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-03 23:15 +0000
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-03 23:15 +0000
1"""
2Shared private/internal IP range constants for security validation.
4Used by SSRF validation and notification URL validation to avoid
5duplicating IP range definitions.
6"""
8import ipaddress
10# RFC1918 private networks + loopback + link-local + CGNAT + IPv6 equivalents
11# nosec B104 - These hardcoded IPs are intentional for security validation
12PRIVATE_IP_RANGES = [
13 ipaddress.ip_network("127.0.0.0/8"), # IPv4 loopback
14 ipaddress.ip_network("::1/128"), # IPv6 loopback
15 ipaddress.ip_network("10.0.0.0/8"), # RFC1918 Class A private
16 ipaddress.ip_network("172.16.0.0/12"), # RFC1918 Class B private
17 ipaddress.ip_network("192.168.0.0/16"), # RFC1918 Class C private
18 ipaddress.ip_network(
19 "100.64.0.0/10"
20 ), # CGNAT - used by Podman/rootless containers
21 ipaddress.ip_network("169.254.0.0/16"), # Link-local
22 ipaddress.ip_network("fe80::/10"), # IPv6 link-local
23 ipaddress.ip_network("fc00::/7"), # IPv6 unique local
24 ipaddress.ip_network("0.0.0.0/8"), # "This" network (IPv4 unspecified)
25 ipaddress.ip_network(
26 "::/128"
27 ), # IPv6 unspecified — Linux routes connections to local host
28 # IPv6 transition prefixes that can wrap private IPv4 destinations.
29 # On Linux hosts with kernel sit0 / NAT64 routes configured, these
30 # prefixes are forwarded to the embedded IPv4 (e.g. 2002:7f00:1::
31 # → 127.0.0.1 via 6to4). Default Linux has no such routes so they
32 # are not exploitable in the typical deployment, but blocking them
33 # closes the gap for operators who do enable transition tunnels.
34 ipaddress.ip_network("2002::/16"), # 6to4 (RFC 3056, deprecated RFC 7526)
35 ipaddress.ip_network("64:ff9b::/96"), # NAT64 well-known prefix (RFC 6052)
36 ipaddress.ip_network(
37 "64:ff9b:1::/48"
38 ), # NAT64 local-use prefix (RFC 8215) — same SSRF threat class as the WKP
39 ipaddress.ip_network("2001::/32"), # Teredo (RFC 4380)
40 ipaddress.ip_network("100::/64"), # IPv6 discard prefix (RFC 6666)
41 # IPv4-Compatible IPv6 — DEPRECATED by RFC 4291 §2.5.5.1 in 2006 but
42 # still parseable by ipaddress and routable on hosts with ::/96 routes
43 # configured (rare but real). Embeds the IPv4 in the low 32 bits so
44 # [::169.254.169.254] would otherwise reach IMDS, identically to the
45 # 6to4/NAT64 wraps. Has zero legitimate live use; blocking it is the
46 # same defense-in-depth move as the transition prefixes above.
47 ipaddress.ip_network("::/96"),
48]
50# NAT64 prefixes — operators on IPv6-only hosts using DNS64+NAT64 reach
51# IPv4 services through these. Blocking by default protects the typical
52# deployment shape (laptops / dual-stack) from the IPv6-wrapped IMDS /
53# RFC1918 SSRF bypass class. Operators who actually need NAT64 reachable
54# can opt in via the env-only setting ``security.allow_nat64``
55# (LDR_SECURITY_ALLOW_NAT64=true). 6to4, Teredo, and discard remain
56# unconditionally blocked — they have no legitimate live use.
57NAT64_PREFIXES = [
58 ipaddress.ip_network("64:ff9b::/96"),
59 ipaddress.ip_network("64:ff9b:1::/48"),
60]