diff --git a/.gitea/actions/review/action.yml b/.gitea/actions/review/action.yml index 1f6d201..de5a9f6 100644 --- a/.gitea/actions/review/action.yml +++ b/.gitea/actions/review/action.yml @@ -10,8 +10,8 @@ # github.server_url. Tokens are never sent to user-supplied URLs. # - On Gitea (VCS_TYPE=gitea), inputs.vcs-url is validated (https scheme, # no whitespace/newlines, and DNS resolution to a public IP) before use. -# Python3 resolves the hostname and rejects RFC1918, loopback, link-local, -# and other reserved addresses to prevent SSRF attacks. +# Python3 resolves the hostname and rejects RFC1918, RFC6598 (carrier-grade +# NAT), loopback, link-local, and other reserved addresses to prevent SSRF attacks. # The installed review-bot binary additionally uses a safe HTTP transport # (DialContext-level IP check) for all Gitea API calls at runtime. # The binary also exposes a `validate-url` subcommand for use in any future @@ -193,7 +193,8 @@ runs: fi # Additional IP-level SSRF defense: resolve the hostname and reject - # requests to RFC1918, loopback, link-local, and other reserved addresses. + # requests to RFC1918, RFC6598 (carrier-grade NAT), loopback, link-local, + # and other reserved addresses. # python3 is required on ubuntu-* runners (see requirements comment above). # Use printf to write the script to a temp file so the python lines are valid # YAML (each indented line becomes a printf argument — no unindented code). @@ -212,7 +213,8 @@ runs: 'for _,_,_,_,(a,*_) in rs:' \ ' ip=ipaddress.ip_address(a)' \ ' if isinstance(ip,ipaddress.IPv6Address) and ip.ipv4_mapped: ip=ip.ipv4_mapped' \ - ' if ip.is_private or ip.is_loopback or ip.is_link_local or ip.is_multicast or ip.is_reserved:' \ + ' cgn=ipaddress.ip_network("100.64.0.0/10")' \ + ' if ip.is_private or ip.is_loopback or ip.is_link_local or ip.is_multicast or ip.is_reserved or ip in cgn:' \ ' print(f"blocked: {a}",file=sys.stderr); sys.exit(1)' \ > /tmp/_ssrf_check.py CHECK_URL="${SERVER_URL}" python3 /tmp/_ssrf_check.py || { @@ -359,7 +361,8 @@ runs: 'for _,_,_,_,(a,*_) in rs:' \ ' ip=ipaddress.ip_address(a)' \ ' if isinstance(ip,ipaddress.IPv6Address) and ip.ipv4_mapped: ip=ip.ipv4_mapped' \ - ' if ip.is_private or ip.is_loopback or ip.is_link_local or ip.is_multicast or ip.is_reserved:' \ + ' cgn=ipaddress.ip_network("100.64.0.0/10")' \ + ' if ip.is_private or ip.is_loopback or ip.is_link_local or ip.is_multicast or ip.is_reserved or ip in cgn:' \ ' print(f"blocked: {a}",file=sys.stderr); sys.exit(1)' \ > /tmp/_ssrf_check_install.py CHECK_URL="${SERVER_URL}" python3 /tmp/_ssrf_check_install.py || {