diff --git a/bbot/scanner/target.py b/bbot/scanner/target.py index 3420b366b1..7823cb39dd 100644 --- a/bbot/scanner/target.py +++ b/bbot/scanner/target.py @@ -82,7 +82,11 @@ def add(self, targets, data=None): targets = [targets] event_seeds = set() for target in targets: - event_seed = EventSeed(target) + # accept pre-parsed EventSeed objects to avoid expensive re-parsing + if isinstance(target, BaseEventSeed): + event_seed = target + else: + event_seed = EventSeed(target) if not event_seed._target_type in self.accept_target_types: log.warning(f"Invalid target type for {self.__class__.__name__}: {event_seed.type}") continue @@ -244,9 +248,9 @@ def __init__(self, seeds=None, target=None, blacklist=None, strict_dns_scope=Fal self.target = ScanTarget(*target_list, strict_dns_scope=strict_dns_scope) # Seeds are only copied from target if target is defined but seeds are NOT defined - # Use target.inputs (original inputs) to preserve all inputs, including subdomains + # Pass pre-parsed event_seeds to avoid expensive re-parsing of every target string if seeds is None: - seeds = self.target.inputs + seeds = list(self.target.event_seeds) self.seeds = ScanSeeds(*list(seeds), strict_dns_scope=strict_dns_scope) blacklist_list = list(blacklist) if blacklist else [] diff --git a/bbot/test/test_step_1/test_target.py b/bbot/test/test_step_1/test_target.py index b9b0cd7fa2..138578b793 100644 --- a/bbot/test/test_step_1/test_target.py +++ b/bbot/test/test_step_1/test_target.py @@ -413,3 +413,31 @@ async def test_blacklist_regex(bbot_scanner, bbot_httpserver): urls = [e.data for e in events if e.type == "URL"] assert len(urls) == 1 assert set(urls) == {"http://127.0.0.1:8888/"} + + +def test_no_double_parsing(): + """Regression test: when seeds are auto-populated from target, EventSeed parsing + should happen only once (via ScanTarget), not twice. BBOTTarget should pass + pre-parsed EventSeed objects to ScanSeeds instead of raw strings.""" + from unittest.mock import patch + from bbot.scanner.target import BBOTTarget + from bbot.core.event.helpers import EventSeed as _real_EventSeed + + targets = ["evilcorp.com", "1.2.3.4", "https://example.com", "10.0.0.0/24"] + + call_count = 0 + original_EventSeed = _real_EventSeed + + def counting_EventSeed(input): + nonlocal call_count + call_count += 1 + return original_EventSeed(input) + + with patch("bbot.scanner.target.EventSeed", side_effect=counting_EventSeed): + BBOTTarget(target=targets) + + # EventSeed should be called once per target (for ScanTarget), not twice + assert call_count == len(targets), ( + f"EventSeed was called {call_count} times for {len(targets)} targets; " + f"expected {len(targets)} (seeds should reuse pre-parsed EventSeed objects)" + )