Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions test_testping1.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand Down
4 changes: 3 additions & 1 deletion testping1.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading