From 67df974789697e3a85ce5fd6cba12a57ecc78dbd Mon Sep 17 00:00:00 2001 From: "aikido-autofix[bot]" <119856028+aikido-autofix[bot]@users.noreply.github.com> Date: Thu, 8 Oct 2026 14:12:38 +0000 Subject: [PATCH] fix(security): Fixed IPv4-mapped IPv6 SSRF bypass by canonicalizing addresses --- .../helpers/ip_matcher_fallback/__init__.py | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/aikido_zen/helpers/ip_matcher_fallback/__init__.py b/aikido_zen/helpers/ip_matcher_fallback/__init__.py index 254a1d7b3..02c7bf493 100644 --- a/aikido_zen/helpers/ip_matcher_fallback/__init__.py +++ b/aikido_zen/helpers/ip_matcher_fallback/__init__.py @@ -3,17 +3,34 @@ MIT License - Copyright (c) 2019 alex """ +import ipaddress from .shared import parse_base_network, sort_networks, summarize_sorted_networks from .sort import binary_search_for_insertion_index +def preparse(network: str) -> str: + """ + Canonicalize IPv4-mapped IPv6 addresses to their IPv4 form. + This ensures that ::ffff:169.254.169.254 matches 169.254.169.254 rules. + """ + # Remove the brackets around IPv6 addresses if they are there. + network = network.strip("[]") + try: + ip = ipaddress.IPv6Address(network) + if ip.ipv4_mapped: + return str(ip.ipv4_mapped) + except ValueError: + pass + return network + + class IPMatcher: def __init__(self, networks=None): self.sorted = [] if networks is not None: subnets = [] for s in networks: - net = parse_base_network(s, False) + net = parse_base_network(preparse(s), False) if net and net.is_valid(): subnets.append(net) sort_networks(subnets) @@ -23,7 +40,7 @@ def has(self, network): """ Checks if the given IP address is in the list of networks. """ - net = parse_base_network(network, False) + net = parse_base_network(preparse(network), False) if not net or not net.is_valid(): return False idx = binary_search_for_insertion_index(net, self.sorted) @@ -36,7 +53,7 @@ def has(self, network): return False def add(self, network): - net = parse_base_network(network, False) + net = parse_base_network(preparse(network), False) if not net or not net.is_valid(): return self idx = binary_search_for_insertion_index(net, self.sorted)