From 5be7fcf6d474c0e24c879c2b2dddfde8f3ed6da3 Mon Sep 17 00:00:00 2001 From: Cobra Date: Mon, 6 Apr 2026 21:57:30 -0400 Subject: [PATCH] Fix module subprocess lifecycle and capture_bus injection bugs Three bugs causing all modules to exit within seconds of startup: 1. _module_runner had no keep-alive loop after calling module.start(). All modules use a thread-spawning pattern where start() returns immediately, so the subprocess exited and killed all daemon threads. Added while module._running: sleep(1) loop to block until stop(). 2. Engine injected capture_bus under key 'capture_bus' but 9 modules (auth_flow_tracker, cloud_token_harvester, ldap_harvester, network_mapper, rdp_monitor, quic_analyzer, smb_monitor, db_interceptor, vlan_discovery) look for '_capture_bus'. Inject both keys so all modules get it. 3. mac_manager crashes on startup when innocuous_macs.db exists but has no mac_profiles table (DB not yet seeded). Added OperationalError handler to fall back to random OUI instead of crashing. --- core/engine.py | 9 +++++++++ modules/stealth/mac_manager.py | 3 +++ 2 files changed, 12 insertions(+) diff --git a/core/engine.py b/core/engine.py index d076b7f..62c1ede 100644 --- a/core/engine.py +++ b/core/engine.py @@ -192,11 +192,18 @@ def _module_runner(module_class: Type[BaseModule], bus_queue: multiprocessing.Qu try: module.start() + # start() is non-blocking — keep subprocess alive while module threads run + while module._running: + time.sleep(1) except Exception: logger.exception("Module %s crashed in start()", module.name) bus_proxy.emit("MODULE_ERROR", {"module": module.name, "error": "start_crash"}, source_module=module.name) finally: + try: + module.stop() + except Exception: + pass state.stop() @@ -357,9 +364,11 @@ class Engine: self.capture_bus = None # Inject capture_bus into module configs for passive modules + # Some modules use "capture_bus", others "_capture_bus" — inject both for name, entry in self._modules.items(): if getattr(entry.module_class, "requires_capture_bus", False): entry.config["capture_bus"] = self.capture_bus + entry.config["_capture_bus"] = self.capture_bus results = {} for name in order: diff --git a/modules/stealth/mac_manager.py b/modules/stealth/mac_manager.py index 838484c..dd61ada 100644 --- a/modules/stealth/mac_manager.py +++ b/modules/stealth/mac_manager.py @@ -210,6 +210,9 @@ class MacManager(BaseModule): if rows: return dict(random.choice(rows)) return None + except sqlite3.OperationalError: + logger.warning("mac_profiles table missing — DB not seeded, using fallback") + return None finally: conn.close()