Metadata-Version: 2.4
Name: summit-scanner
Version: 0.6.8
Summary: Summit - open-source web security testing platform (proxy, scanner, fuzzer) by Pennacle Security
Author: Pennacle Security
License: MIT
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.31
Requires-Dist: pyyaml>=6.0
Requires-Dist: packaging>=23.0
Dynamic: license-file

<p align="center">
  <img src="docs/assets/banner.png" alt="summit" width="760">
</p>

<p align="center">
  <a href="https://github.com/pennacle-security/summit/actions/workflows/tests.yml"><img src="https://github.com/pennacle-security/summit/actions/workflows/tests.yml/badge.svg" alt="CI status"></a>
  <a href="https://github.com/pennacle-security/summit/releases"><img src="https://img.shields.io/github/v/tag/pennacle-security/summit?label=release&color=2ea44f" alt="release"></a>
  <a href="https://pypi.org/project/summit-scanner/"><img src="https://img.shields.io/pypi/v/summit-scanner?color=2ea44f" alt="PyPI"></a>
  <a href="https://www.bestpractices.dev/projects/15532"><img src="https://www.bestpractices.dev/projects/15532/badge" alt="CII Best Practices"></a>
  <a href="https://api.scorecard.dev/projects/github.com/pennacle-security/summit/badge"><img src="https://api.scorecard.dev/projects/github.com/pennacle-security/summit/badge" alt="OpenSSF Scorecard"></a>
  <a href="https://pennacle-security.github.io/summit/"><img src="https://img.shields.io/badge/docs-live-2ea44f" alt="docs"></a>
  <img src="https://img.shields.io/badge/python-3.10%2B-3776ab" alt="python 3.10+">
  <img src="https://img.shields.io/github/license/pennacle-security/summit?color=8b949e" alt="MIT license">
</p>

<p align="center">One scriptable CLI for web security testing: scanner, proxy, fuzzer, authorization testing, WAF analysis, link-hijack detection and recon.<br>Free where the equivalents are paid - by <a href="https://github.com/pennacle-security">Pennacle Security</a>.</p>

---

We use Burp and ZAP every day. We also kept wanting three things they are not: a scanner we can script against in CI, findings that tell us how sure they are, and a codebase small enough to read in one sitting. Summit is that tool - v0.6, MIT, a single `pip install summit-scanner` away, built in the open.

**Full documentation:** [pennacle-security.github.io/summit](https://pennacle-security.github.io/summit/)

## Contents

1. [At a glance](#at-a-glance)
2. [Quick start](#quick-start)
3. [Proof, not promises](#proof-not-promises)
4. [Commands](#commands)
5. [Feature notes](#feature-notes)
6. [Anti false positives and false negatives](#anti-false-positives-and-false-negatives)
7. [Check catalog](#check-catalog)
8. [How summit compares](#how-summit-compares)
9. [Roadmap](#roadmap)
10. [Community and contributors](#community-and-contributors)
11. [Contributing and security](#contributing-and-security)
12. [Legal and license](#legal-and-license)

## At a glance

Capabilities that usually sit behind paid tooling, plus the scanning core:

| Capability | Summit | The usual route |
|---|---|---|
| Broken access control testing (BOLA/IDOR) | `summit authorize` | Autorize-style add-on / paid workflows |
| Hidden parameter discovery | `summit mine` | Param Miner-style add-on |
| OpenAPI-driven scanning | `summit scan --openapi` | add-ons |
| WAF fingerprinting + bypass probing | built in | partial / add-ons |
| Broken-link hijack detection | built in | paid extension |
| SQLi, XSS, redirect, traversal, takeover, host header, CORS | built in | core scanners (free) |
| Recon chain: subfinder -> httpx -> nmap | `summit recon` | manual gluing |
| Rate limiting, retries, JWT/encoder toolkit | built in | add-ons / paid |
| CI-ready, confidence-labelled findings | the whole point | paid automation |

Every finding carries a confidence label: `confirmed` (an observed fact) or `potential` (a heuristic). That distinction runs through the entire tool.

## Quick start

```bash
pip install summit-scanner        # from PyPI
# or from a git checkout:
git clone https://github.com/pennacle-security/summit.git
cd summit
pip install -e .
```

Python 3.10+. Then watch it work against a deliberately vulnerable local target:

```bash
python examples/vuln_app.py        # terminal 1 - the target (127.0.0.1 only)
summit scan http://127.0.0.1:8765  # terminal 2 - the scan
```

A fuller pass on a real engagement looks like this:

```bash
summit recon target.com --json recon.json                 # subdomains -> hosts -> ports
summit scan https://target.com --depth 2 --rate 10        # crawl + all checks
summit scan --openapi api-spec.json                       # API: scan what the spec admits to
summit authorize https://target.com/admin?user=1 \
  --role 'admin=Cookie: session=abc' \
  --role 'user=Cookie: session=xyz'                       # BOLA/IDOR testing
```

## Proof, not promises

Every claim on this page is reproduced by [`examples/evidence.py`](examples/evidence.py) - it runs the demo target live, measures each feature, and prints PASS/FAIL with the real numbers. CI executes it on every push; a claim that stops holding fails the build.

<details>
<summary>Latest measured run (<code>python examples/evidence.py</code>)</summary>

```text
[PASS] full scan: 16 seeded check families detected, zero false positives
       53 findings in 22.9s (344 requests), missing=none, control link flagged=no, 19 finding(s) carry confidence=confirmed
[PASS] resource takeover fingerprint detected on the target's own 404
       Possible AWS S3 resource takeover | AWS S3: 'nosuchbucket'
[PASS] host header injection: marker domain echoed back by the app
       Host: summit-host-probe.example -> reflected (reset-link poisoning surface)
[PASS] CORS reflects an arbitrary origin with credentials allowed
       ACAO: https://summit-cors-probe.example; ACAC: true
[PASS] WAF bypass: naive filter blocks, tampered payload lands decoded
       raw payload -> HTTP 403 (blocked); URL-encoded once -> HTTP 200, payload reflected decoded: True
[PASS] CAPTCHA challenge detected (reported, not solved)
       /login -> reCAPTCHA via marker 'recaptcha/api.js'
[PASS] rate limiting: --rate 5 paces 12 requests to ~2.2s; unlimited runs free
       12 requests at rate 5 -> 2.20s (theoretical floor: 2.2s); 12 requests unlimited -> 0.02s
[PASS] concurrency on a latency-bearing target: 8 workers vs serial
       40 requests x 25ms latency: serial 1.33s -> parallel 0.18s (7.3x speedup)
[PASS] smart prioritizer ranks known-injectable parameters first
       probing starts with: [('query', 'search?query=laptop'), ('id', 'user?id=1'), ('url', 'example.com')]
[PASS] toolkit decodes JWT header/payload and states the signature is unverified
       signature NOT verified - decoding only
[PASS] update check compares versions numerically (0.3 < 0.10)
       is_outdated('0.3.0', '0.10.0') -> True; is_outdated('1.0.0', '0.9.9') -> False
[PASS] broken access control: admin panel served identically to a low-privilege role
       verdict=broken; finding=Broken access control (BOLA/IDOR candidate)
[PASS] hidden parameter mining finds the undocumented debug parameter, zero noise
       1 finding(s): ['debug'] (all confirmed reflections)
[PASS] openapi-driven scan: spec alone leads the engine to seeded SQLi and XSS
       2 spec target(s) scanned -> 10 findings, sqli-error=yes, xss-reflection=yes
[PASS] OS command injection: marker executed and echoed by the server
       semicolon: exec marker x2, control marker x1 | CWE-78
[PASS] server-side template injection: {{7*7}} came back as 49
       Jinja2/Twig: {{7*7}} -> 49 | CWE-1336
[PASS] CRLF injection: X-Summit-CRLF header materialized in the response
       X-Summit-CRLF: injected | CWE-113
[PASS] sensitive file exposure: /.env confirmed by content signature
       content signature: 'APP_KEY=' | CWE-538
[PASS] CVE detection: Apache/2.4.49 banner maps to known CVEs
       detect_cves('Apache/2.4.49') -> ['CVE-2021-41773', 'CVE-2021-42013']

evidence summary: 19/19 claims verified
```

</details>

A visual of a real scan against the demo target:

<p align="center">
  <img src="docs/assets/demo.png" alt="real summit scan output against the local demo target" width="760">
</p>

Reproduce everything yourself:

```bash
python examples/vuln_app.py    # terminal 1 - the target
summit scan http://127.0.0.1:8765
python examples/evidence.py    # re-verify every claim above
```

The demo seeds a *healthy* outbound link (`https://example.com`) as a negative control - it must never be reported, and CI asserts that alongside the seeded detections. Found something wrong anyway? [Report it](https://github.com/pennacle-security/summit/issues/new?template=bug_report.yml).

## Commands

| Command | What it does |
|---|---|
| `summit scan <url>` | crawl, then passive + active checks, link health, WAF analysis. `--openapi` scans a spec instead of crawling. `--json` / `--html` reports. |
| `summit authorize <url...>` | BOLA/IDOR testing: compare responses between two roles. |
| `summit mine <url>` | hidden parameter discovery (~70 candidates, marker-based). |
| `summit fuzz <url>` | directory brute force with wildcard-baseline filtering. |
| `summit recon <domain>` | chain subfinder -> httpx -> nmap into one report. |
| `summit tls <host>` | certificate expiry / self-signed / legacy TLS version audit. |
| `summit proxy` | intercepting HTTP proxy with a SQLite site map. |
| `summit repeater <file>` | send a raw request file (Burp-style). |
| `summit encode` / `summit decode` | base64, URL, hex, JWT (decode-only, honestly unverified). |
| `summit --check-update` / `--auto-update` / `--install-tools` | versioning and recon tool installer. |

Shared flags on scanning commands: `--workers`, `--rate` (requests/second ceiling), `--retries` (with `Retry-After` support), `--timeout`, `--delay`.

## Feature notes

**Authorization testing.** Requests each URL as a privileged and a low-privilege role, then compares. Verdicts: `enforced` (roles differ), `broken` (identical response for the low-privilege role - critical, `confirmed`), `partial` (same status, different body - `potential`). Measured on the demo: the admin panel serves salaries to both roles, caught as `confirmed`.

**Hidden parameter mining.** Servers read parameters the HTML never mentions - debug switches, feature flags, internal overrides. ~70 candidate names are probed with unique markers; reflection findings are `confirmed`, status/size shifts are `potential`. Measured: the demo's undocumented `debug` switch found as `confirmed`, the other candidates silent - zero noise.

**OpenAPI-driven scanning.** Every documented endpoint becomes a target, with path params filled from examples and defaults - no crawling, no guessing. Measured: the spec alone leads the engine to the seeded SQLi and XSS. JSON and YAML specs are read natively.

**WAF detection and bypass.** Tight vendor signatures for Cloudflare, AWS WAF, Akamai, Imperva, ModSecurity, Sucuri, F5 and Wordfence. When a filter blocks standard payloads, tamper variants (single/double URL-encoding, comment splitting, case alternation) are tried - and a bypass is reported only when the original payload lands **decoded** in the response. Measured: raw payload -> HTTP 403; encoded once -> HTTP 200, decoded.

**OS command injection, SSTI, CRLF, sensitive files.** New in v0.6, each with a hard confirmation rule: OS command injection uses an exec marker plus a control probe (a server that merely reflects input shows both markers; a server that executes shows the exec marker more often - measured `x2 vs x1`), SSTI requires `{{7*7}}` to come back as `49`, CRLF requires our injected header to materialize, and sensitive files (`.env`, `.git/config`, backups) require a content signature - never just a 200. Every finding is tagged with its CWE automatically (CWE-78, CWE-1336, CWE-113, CWE-538), and version banners are matched against an offline CVE database (spoofable banners stay `potential`).

**CAPTCHA: detect, do not solve.** reCAPTCHA, hCaptcha, Cloudflare Turnstile and challenge pages are detected and reported. Solving them automatically is out of scope by design - that line does not move.

**Broken-link hijacking.** Every outbound link is health-checked: dead domains (DNS verified twice), parked domains (tight fingerprints), broken links (404/410), unreachable hosts, and private-target links - recorded but never fetched, so a hostile page cannot weaponize your scanner as an SSRF probe.

**Resource takeover fingerprints.** A 404 answered with a provider's unclaimed-resource page (AWS S3, GitHub Pages, Heroku, Azure, Shopify, Fastly, Pantheon, Tumblr, Surge, Bitbucket) is a takeover setup. Fingerprint-only: no DNS tricks, no active claiming, ever.

**Recon orchestration.** subfinder -> httpx -> nmap, whichever are installed, with defensive parsing: passive-DNS noise capped, per-tool timeouts degrade into notes, and a crashed nmap is reported as *failed* - never as "no open ports".

**Rate limiting and prioritization.** `--rate` is a thread-safe requests/second ceiling (measured: 12 requests paced to 2.20s at rate 5; 0.02s unlimited). A transparent scoring model orders high-signal parameters first - deterministic and auditable, deliberately not a "neural network" claim.

**Toolkit and updates.** JWT decode with an honest "signature NOT verified" note, base64/URL/hex both directions, numeric version comparison against GitHub releases (`0.3 < 0.10`), self-update from a git checkout.

## Anti false positives and false negatives

False positives waste your triage time. False negatives get clients breached. Summit engineers against both, and the evidence runner proves it:

| Mechanism | What it kills |
|---|---|
| **Two-stage XSS check** - a unique canary goes first; payloads only fire on parameters that actually reflect | payload noise on parameters that never reflect |
| **Baseline diffing** - every probe compared against the same request untouched | error strings already sitting in the page |
| **Divergence + baseline match** (boolean SQLi) - `AND 1=1` must match the baseline, `AND 1=2` must differ | pages that simply vary per request |
| **Wildcard baseline** (fuzzer) - a random nonexistent path is measured first | "everything returns 200" servers flooding the report |
| **DNS double-check** (linkcheck) - a host must fail to resolve twice | transient resolver hiccups becoming fake hijack reports |
| **SSRF guard** - private/link-local/metadata ranges recorded, never fetched | your scanner weaponized against internal networks |
| **Tamper honesty** (WAF bypass) - requires the payload decoded in the response | bypass reports that would not survive a browser |
| **Tracker/opaque param filter** - `utm_*`, `fbclid`, 40+ char tokens never probed | wasted requests and padded reports |
| **Negative control in CI** - a healthy link that must stay unreported, asserted every push | silent regressions into false-positive territory |
| **Scope lock** - the spider never leaves the target host | crawling half the internet, and legal exposure |
| **Confidence labels** - fact vs heuristic, on every finding | one flat "everything is critical" triage queue |
| **Unbreakable probe hosts** - `.example` cannot resolve | third-party callbacks and accidental DoS |

## Check catalog

| Check | Type | Severity | Confirmation basis |
|---|---|---|---|
| Missing security headers | passive | low | header absence |
| Cookie flags (Secure / HttpOnly / SameSite) | passive | low-medium | header parse |
| SQL error / stack-trace disclosure | passive | medium | baseline-diffed signatures |
| Server and tech version disclosure | passive | info | header parse |
| CORS wildcard with credentials | passive | low | header parse |
| Email exposure | passive | info | regex |
| WAF fingerprint | passive | info | tight vendor signatures |
| CAPTCHA / anti-bot challenge | passive | info | challenge markers, reported not solved |
| Resource takeover signature | passive | high | provider unclaimed-resource page on 404 -> `confirmed` |
| SQL injection, error-based | active | critical | fresh DB error vs baseline -> `confirmed` |
| SQL injection, boolean-based | active | critical | response divergence -> `potential` |
| SQL injection, time-based blind | active | critical | calibrated delay reproduced on every probe -> `potential` |
| GraphQL introspection enabled | passive-origin | low | real `__schema` payload -> `confirmed` |
| Reflected XSS | active | high | canary + raw payload reflection -> `confirmed` |
| WAF filter bypass | active | high | tampered payload lands decoded -> `confirmed` |
| Host header injection | active | high | marker domain echoed vs baseline -> `confirmed` |
| CORS origin reflection | active | high | arbitrary origin reflected + credentials -> `confirmed` |
| OS command injection | active | critical | exec marker outruns control marker -> `confirmed`, CWE-78 |
| Server-side template injection (RCE) | active | critical | `{{7*7}}` evaluates to 49 -> `confirmed`, CWE-1336 |
| CRLF injection / response splitting | active | high | injected header materializes -> `confirmed`, CWE-113 |
| Sensitive file exposure (.env, .git) | passive-origin | high | content signature, not just a 200 -> `confirmed`, CWE-538 |
| Known CVE in version banner | passive | high | offline CVE database match -> `potential` (banners spoof) |
| Open redirect | active | medium | 3xx Location to probe host -> `confirmed` |
| Path traversal | active | high | OS file indicators -> `confirmed` |
| Broken access control (BOLA/IDOR) | authorize | critical | identical response for low-privilege role -> `confirmed` |
| Hidden parameter (reflected) | mine | medium | unique marker reflected -> `confirmed` |
| Hidden parameter (behavior) | mine | low | status/size shift -> `potential` |
| Link to dead domain (hijack) | linkcheck | high | DNS failure, verified twice -> `confirmed` |
| Link to parked domain (hijack) | linkcheck | high | tight parking fingerprints -> `confirmed` |
| Broken outbound link | linkcheck | medium | HTTP 404/410 -> `confirmed` |
| Unreachable outbound link | linkcheck | low | fails after retry -> `potential` |
| Outbound link to private IP | linkcheck | info | DNS resolution -> `confirmed`, never fetched |
| TLS certificate expired / self-signed | tls | high-medium | certificate dates and issuer -> `confirmed` |
| Legacy TLS versions accepted | tls | medium | handshake completed with TLSv1.0/1.1 -> `confirmed` |
| Directory fuzz | fuzz | info | status + wildcard baseline |

## How summit compares

| | summit | ZAP | Burp Suite |
|---|---|---|---|
| Price | free, MIT | free | paid core |
| UI | CLI + HTML/JSON reports | full GUI | full GUI |
| Scriptable in CI | yes, that is the point | add-ons | paid automation |
| Confidence-labelled findings | yes | partial | partial |
| Authorization testing (Autorize-style) | built in, scriptable | add-on | paid workflows |
| Hidden parameter mining (Param Miner-style) | built in | add-on | add-on |
| OpenAPI-driven scanning | built in | add-on | add-on |
| WAF detection + bypass probing | built in | partial | partial |
| Broken-link hijacking | built in | add-on | paid extension |
| Rate limiting | built in, thread-safe | add-on | paid |
| JWT/encoder toolkit | built in | add-on | built in |
| Takeover fingerprints, host header, CORS | built in | add-ons | add-ons |
| Codebase you can audit in an afternoon | ~3.6k lines | large | closed source |
| TLS-intercepting proxy | on the roadmap | yes | yes |

We are not trying to replace either of them. Summit is the small tool you drop into a pipeline or onto a VPS box, and the codebase you can actually read line by line.

## Roadmap

- [ ] TLS interception in the proxy (generated CA)
- [ ] POST form and JSON body injection points
- [ ] Authenticated scanning (cookies, headers)
- [ ] CNAME-level subdomain takeover (DNS resolution + service verification)
- [ ] Plugin API for custom checks
- [ ] Request interception UI

## Community and contributors

A repository that helps people back grows through word-of-mouth:

- **Questions** -> [Q&A discussion](https://github.com/pennacle-security/summit/discussions/categories/q-a) - beginner questions welcome, answered gladly
- **Ideas & roadmap votes** -> [Ideas](https://github.com/pennacle-security/summit/discussions/categories/ideas)
- **Show what you scanned** -> [Show and tell](https://github.com/pennacle-security/summit/discussions/categories/show-and-tell)
- **Your first contribution** -> [good first issues](https://github.com/pennacle-security/summit/labels/good%20first%20issue) come with step-by-step instructions
- First issues and PRs get a personal review and a spot below; the welcome bot says hello too

If summit saved you time on an engagement, a star helps the next person find it.

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->

<table>
  <tbody>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/SakarPaisen"><img src="https://avatars.githubusercontent.com/u/141169555?v=4?s=100" width="100px;" alt="SakarPaisen"/><br /><sub><b>SakarPaisen</b></sub></a><br /><a href="https://github.com/pennacle-security/summit/commits?author=SakarPaisen" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/mrvi0"><img src="https://avatars.githubusercontent.com/u/196581611?v=4?s=100" width="100px;" alt="mrvi0"/><br /><sub><b>mrvi0</b></sub></a><br /><a href="https://github.com/pennacle-security/summit/commits?author=mrvi0" title="Code">💻</a></td>
    </tr>
  </tbody>
</table>

<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->

## Contributing and security

PRs welcome - the [contributing guide](https://github.com/pennacle-security/.github/blob/main/CONTRIBUTING.md) covers the process, and adding a scan check is roughly thirty lines if you follow the pattern. [examples/vuln_app.py](examples/vuln_app.py) gives you a live target to test against.

Security issues go through private disclosure only. Details in the [security policy](https://github.com/pennacle-security/.github/blob/main/SECURITY.md).

## Legal and license

Summit is built for authorized security testing: your own systems, or systems you have written permission to test. We are not responsible for misuse. Licensed under [MIT](LICENSE).
