#!/usr/bin/env python3 """ Dump the Flask url_map to a file as one absolute URL per line. Used by the Nuclei DAST workflow to seed a URL list so the scanner probes the actual application surface (authenticated routes, API endpoints, blueprints) instead of just the index page. Parameterized routes (`/research//status`) are emitted with a converter-appropriate placeholder so Nuclei still exercises the path. The substituted URL will usually 404 (the resource doesn't exist for the test user), but that is fine — Nuclei probes path traversal, parameter injection, and SQLi templates against the URL pattern, not against a specific resource. Skips: - The Flask `static` endpoint (asset serving, no app logic). - Routes that don't accept GET — Nuclei templates almost exclusively issue GET probes, so POST-only endpoints just generate 405s. Usage: python scripts/ci/dump_url_map.py http://127.0.0.1:5000 > urls.txt """ import re import sys # Map Flask URL converters to a placeholder that satisfies the converter # so Flask routes the request to the handler instead of 404-ing at the # converter stage. Anything not listed falls back to a plain string. _PLACEHOLDERS = { "int": "1", "float": "1", "uuid": "00000000-0000-0000-0000-000000000000", } _DEFAULT_PLACEHOLDER = "nuclei" _PARAM_RE = re.compile( r"<(?:(?P[a-zA-Z_][a-zA-Z0-9_]*)(?:\([^)]*\))?:)?(?P[a-zA-Z_][a-zA-Z0-9_]*)>" ) def _substitute(match: "re.Match[str]") -> str: return _PLACEHOLDERS.get(match.group("conv") or "", _DEFAULT_PLACEHOLDER) def main() -> int: if len(sys.argv) != 2: print(f"Usage: {sys.argv[0]} BASE_URL", file=sys.stderr) return 2 base_url = sys.argv[1].rstrip("/") from local_deep_research.web.app_factory import create_app app, _ = create_app() seen: set[str] = set() for rule in app.url_map.iter_rules(): if rule.endpoint == "static": continue if "GET" not in (rule.methods or set()): continue path = _PARAM_RE.sub(_substitute, rule.rule) url = f"{base_url}{path}" if url in seen: continue seen.add(url) print(url) return 0 if __name__ == "__main__": sys.exit(main())