Parse WhatWeb JSON result
(self, data: Dict, scan_id: str)
| 1918 | # Add Cookie if provided |
| 1919 | if options.get('cookie_value'): |
| 1920 | cmd.extend(['-H', f'Cookie: {options["cookie_value"]}']) |
| 1921 | |
| 1922 | # Add custom headers if provided |
| 1923 | if options.get('headers'): |
| 1924 | for header in options['headers']: |
| 1925 | cmd.extend(['-H', header]) |
| 1926 | |
| 1927 | logger.debug(f"Running Nuclei: {' '.join(cmd)}") |
| 1928 | |
| 1929 | # stdout goes to the -o file; route process stdout to DEVNULL and |
| 1930 | # stderr to a file so the pipe buffer can never fill and deadlock, |
| 1931 | # and so we can read the real error message afterwards. |
| 1932 | errf = open(stderr_path, 'w') |
| 1933 | try: |
| 1934 | process = subprocess.Popen( |
| 1935 | cmd, |
| 1936 | stdout=subprocess.DEVNULL, |
| 1937 | stderr=errf, |
| 1938 | text=True, |
| 1939 | env={**os.environ, **nuclei_env}, |
| 1940 | # New session when wrapped so we can kill the whole group |
| 1941 | # (systemd-run scope + nuclei) on cancel/timeout. |
| 1942 | start_new_session=use_session, |
| 1943 | ) |
| 1944 | if use_session: |
| 1945 | self._session_leader_pids.add(process.pid) |
| 1946 | self._register_scan_process(scan_id, process) |
| 1947 | |
| 1948 | # Monitor progress with a hard runtime cap so a hung nuclei |
| 1949 | # process cannot block the scan thread indefinitely. |
| 1950 | max_runtime = int(options.get('max_runtime', 1800)) |
| 1951 | start_time = time.monotonic() |
| 1952 | # Small initial bump so the bar isn't frozen at 0 before |
| 1953 | # nuclei's first stats line (which -si 5 emits after ~5s). |
| 1954 | progress.progress_percent = max(progress.progress_percent, 3) |
| 1955 | while process.poll() is None: |
| 1956 | time.sleep(2) |
| 1957 | if self._is_scan_cancelled(scan_id): |
no test coverage detected