Architecture
Summit is deliberately small (~3.1k lines). This page is the map so you can fix or extend things without archaeology.
Layout
summit/
├── http/ models (raw request parsing, response) + client (rate limit, retries, TLS controls)
├── crawl/ breadth-first spider with same-host scope + external-link collection
├── scan/
│ ├── core.py Finding (confidence labels!), InjectionPoint, Check base class
│ ├── passive.py header/cookie/body checks, WAF + CAPTCHA + takeover wiring
│ ├── engine.py orchestration: passive pass, prioritized active pass (ThreadPool), link health
│ ├── linkcheck.py broken-link hijacking: DNS double-check, parking fingerprints, SSRF guard
│ ├── smart.py adaptive probe prioritizer (transparent scoring)
│ └── modules/ one file per active check - the pattern to copy
├── waf.py WAF fingerprint database
├── captcha.py challenge detection (report, never solve)
├── takeover.py provider unclaimed-resource fingerprints
├── ratelimit.py thread-safe client-side rate limiter (injectable clock)
├── recon.py subfinder / httpx / nmap orchestration with defensive parsing
├── proxy/ intercepting HTTP proxy + SQLite site map
├── report/ console, JSON and HTML writers
├── toolkit.py JWT / base64 / URL / hex
├── updates.py version check, self-update, tool installer
└── cli.py argparse wiring and command implementations
Data flow of a scan
summit scan <url>
│
├── Spider.crawl() same-host BFS; GET forms are requeued as query URLs;
│ external links are recorded, not followed
│
├── passive checks per page: headers, cookies, error leaks, WAF,
│ CAPTCHA, takeover fingerprints
│
├── build_targets() query params -> InjectionPoints; trackers and
│ + smart.prioritize() opaque tokens skipped; high-signal names first
│
├── active checks ThreadPool(workers): SQLi, XSS, WAF bypass,
│ host header, CORS, redirect, traversal
│
├── linkcheck each unique outbound URL once: DNS (twice on
│ failure) -> private-range guard -> streaming GET
│
└── report console / JSON / HTML, sorted by severity
The rules every module obeys
- Findings are facts first. If the check cannot show the evidence, it stays
potentialor stays quiet. - Baseline diffing. Compare against an unmodified request; static content is not a finding.
- Safe defaults. Probe hosts that cannot resolve (
.example), localhost-only demo targets, never fetch private ranges, never solve challenges. - A broken check must not kill the scan. Exceptions are captured into
engine.errorsand printed.
The full reasoning lives in the README's anti-FP section; the enforcement lives in CI (smoke test + evidence runner).