diff --git a/test_testping1.py b/test_testping1.py index a3fcd04..622fbbd 100644 --- a/test_testping1.py +++ b/test_testping1.py @@ -246,6 +246,19 @@ def test_is_reachable_ipv6_scope_id_validation(self, mock_call): self.assertIn("Invalid IPv6 scope ID: IPv6Address('fe80::1%eth0\\nERROR:root:Compromised')", log.output[0]) mock_call.assert_not_called() + @patch('testping1.subprocess.call') + def test_is_reachable_ipv6_scope_id_length_limit(self, mock_call): + """Test is_reachable enforces strict length limit on IPv6 scope IDs.""" + import ipaddress + # Max Linux IFNAMSIZ is 15. Provide 16 chars. + malicious_ip_obj = ipaddress.IPv6Address('fe80::1') + malicious_ip_obj._scope_id = 'a' * 16 + + with self.assertLogs(level='ERROR') as log: + self.assertFalse(is_reachable(malicious_ip_obj)) + self.assertIn("Invalid IPv6 scope ID:", log.output[0]) + mock_call.assert_not_called() + @patch('testping1.subprocess.call') def test_is_reachable_subprocess_timeout(self, mock_call): """Test is_reachable handles subprocess.TimeoutExpired securely.""" diff --git a/testping1.py b/testping1.py index 63e23a5..9393a6b 100644 --- a/testping1.py +++ b/testping1.py @@ -15,7 +15,9 @@ # Calling re.compile() once at module load avoids the overhead of parsing and compiling # the regular expression (or looking it up in the internal cache) during every is_reachable() execution. # This yields a measurable CPU speedup when firing thousands of concurrent pings. -SCOPE_ID_REGEX = re.compile(r'[\w\-]+') +# 🛡️ Sentinel: Enforce strict length limits (1-15 chars) and explicit ASCII charset +# to prevent resource exhaustion or unexpected OS behavior from overly long/Unicode scope IDs. +SCOPE_ID_REGEX = re.compile(r'[a-zA-Z0-9_\-]{1,15}') # ⚡ Bolt: Cache the absolute path of the ping executable. # Calling shutil.which() once at module load avoids the overhead of traversing