Metadata-Version: 2.4
Name: recon-orchestrator
Version: 1.2.1
Summary: Authorized security-scan tool orchestrator (nmap/nuclei/testssl + built-in checks) with Markdown/JSON/SARIF reports.
License-Expression: Apache-2.0
Keywords: security,pentesting,recon,nuclei,nmap,sarif,appsec
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Security
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.28
Requires-Dist: pyyaml>=6.0
Provides-Extra: dns
Requires-Dist: dnspython>=2.4; extra == "dns"
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: ruff>=0.6; extra == "dev"
Requires-Dist: mypy>=1.8; extra == "dev"
Requires-Dist: types-requests; extra == "dev"
Requires-Dist: dnspython>=2.4; extra == "dev"
Dynamic: license-file

# recon-orchestrator

[![ci](https://github.com/m0Corut/recon-orchestrator/actions/workflows/ci.yml/badge.svg)](https://github.com/m0Corut/recon-orchestrator/actions/workflows/ci.yml)
![license](https://img.shields.io/badge/license-Apache--2.0-blue)
![python](https://img.shields.io/badge/python-3.9%2B-blue)

**[English](#english)** | **[Türkçe](#türkçe)**

---

## English

### What is this?

`recon-orchestrator` is a command-line tool that checks a website, API, or
domain for common, well-known security misconfigurations — the kind of issues
that show up in almost every real-world penetration test: missing security
headers, exposed databases, outdated TLS, weak SPF/DMARC email records, leaky
API endpoints, pages that should require login but don't, and more.

It does **not** reinvent scanning from scratch. Instead it **orchestrates**
battle-tested, industry-standard open-source tools — [nmap](https://nmap.org)
(port scanning), [nuclei](https://github.com/projectdiscovery/nuclei)
(vulnerability templates), [testssl.sh](https://github.com/drwetter/testssl.sh)
(TLS auditing) — plus its own lightweight Python checks, runs them all against
one target, merges every result into one consistent format, and hands you a
single report instead of six different tool outputs to cross-reference by
hand.

**Who it's for:** developers and small teams who want a free, repeatable
security check of their own site before shipping, in CI, or on a schedule —
without paying for a commercial scanning platform or learning six separate
tools.

### Why use it instead of running the tools yourself?

You *could* run nmap, nuclei, and testssl.sh by hand — many people do. This
tool exists because that gets tedious fast:

- **One command, one report.** Instead of six terminal windows and six output
  formats, you get one Markdown/HTML report (for humans) and one JSON/SARIF
  report (for machines and CI).
- **Noise reduction.** Raw tool output is full of false-positive-prone,
  terminology-heavy lines. This project turns each one into a plain-language
  finding with a severity and a recommendation.
- **CI-friendly out of the box.** `--fail-on-new high` fails your build only
  when a *new* high-severity issue appears, not every time because of an
  old, already-known, accepted issue — so it's realistic to run on every pull
  request without constant red builds.
- **No vendor lock-in, no subscription, no LLM cost.** Everything here runs
  with free, open tools. An optional AI "executive summary" exists, but it is
  off by default and the tool is fully useful without it.

### How it works

When you run `recon <target> --authorized`, four things happen in order:

1. **Scope is locked.** The tool resolves your target's hostname and builds an
   allow-list (by default: just that one host). Every HTTP request any module
   makes — including following a redirect — is checked against this list
   first. This exists so that a redirect on the target site can never make the
   tool silently start probing some unrelated third-party domain.

2. **Modules run, in parallel, under a shared speed limit.** Each check
   (`headers`, `ports`, `tls`, …) is an independent Python module. They run
   concurrently so the slow ones (nmap, nuclei, testssl — these can take
   minutes) overlap instead of stacking up, which roughly halves total scan
   time. All modules that send real HTTP traffic share one request-rate budget
   (`--rate`, requests/second) so running things in parallel never increases
   load on the target beyond what you set.

3. **Results are merged and de-duplicated.** Every single finding gets a
   stable identifier (`rule_id`) and a fingerprint, independent of wording or
   language. If two modules happen to report the same underlying issue, it's
   only counted once. This same fingerprint is what makes run-to-run diffing
   possible (see below).

4. **Reports are written.** Four files land in `recon_runs/<host>_<timestamp>/`:
   a Markdown report to read, a JSON report for scripting, a SARIF file for
   GitHub's "Code scanning" UI, and a self-contained HTML page you can open in
   a browser or attach to an email — with no external resources loaded (your
   scan results never leave your machine unless you choose to send them
   somewhere).

On every subsequent scan of the *same* host, the tool automatically looks at
your last run and tells you what's **new** versus what you already knew
about — so a CI pipeline using `--fail-on-new` only turns red when something
actually changed for the worse.

### Installation

You need **Python 3.9 or newer**. Everything else is optional depending on
which modules you want:

| You want... | You need |
|---|---|
| The core checks (headers, CORS, content discovery) | Just Python + pip |
| DNS/email security (`dns`) and mail (`mail`) checks | the `[dns]` extra |
| Port scanning, TLS audit, nuclei templates (`ports`/`tls`/`web`) | Docker **or** the tools installed natively |
| Subdomain inventory (`--discover`) | nothing extra; the `[dns]` extra adds CNAME/takeover checks, and subfinder (Docker or native) adds more sources |
| Endpoint crawl (`crawl` module) | katana (Docker or native); `--crawl-headless` also needs Chromium |
| Injection fuzzing (`--dast`) | nuclei (Docker or native); an OpenAPI/Swagger spec **or** a crawl of the site |

**Option A — install from PyPI (recommended):**

```bash
pip install "recon-orchestrator[dns]"            # omit [dns] if you don't need dns/mail
pip install "recon-orchestrator[dns]==1.2.1"     # or pin an exact version (e.g. in CI)
pip install -U "recon-orchestrator[dns]"         # upgrade an existing install
```

This installs a `recon` command on your PATH; `recon --version` shows which
version you have.

**Option B — clone and install (to read or change the code):**

```bash
git clone https://github.com/m0Corut/recon-orchestrator
cd recon-orchestrator
pip install ".[dns]"
```

**Option C — Docker image (zero local setup, tools included):**

If you don't want to install Python packages or Docker-pull individual tool
images, use the all-in-one image. It bundles nmap, nuclei, testssl.sh and
subfinder as native binaries inside the container, so it needs *only* Docker
itself:

```bash
docker run --rm -v "$PWD:/work" ghcr.io/m0corut/recon-orchestrator:1.2.1 \
  https://example.com --authorized
```

Use a version tag such as `:1.2.1` so a scan does not change underneath you;
`:latest` always points at the newest release.

**Tool versions.** When the tools run through Docker, recon uses pinned
images (nmap 7.98, nuclei v3.11.1, testssl.sh 3.2, subfinder v2.17.0), so the
same recon version always scans with the same tools. Tools you installed
natively are used as they are, whatever their version. With the default
`--runner auto`, native binaries are used when nmap, nuclei and testssl.sh are
all installed; otherwise Docker is used. subfinder is optional either way.

**Checking your setup:** after installing, run `recon doctor` — it tells you
exactly which tools and optional packages it can see, so you know in advance
which modules will actually run.

**Upgrading from 1.0.** Nothing breaks: every new feature in 1.1 is off until
you ask for it (`--discover`, `--dast`, `--notify-env`, `--resume`), with one
exception: if a `.reconignore.yml` file exists in the directory you scan from,
it is now read automatically. Scans also keep a small checkpoint in
`recon_runs/.partial/` while they run, and remove it when they finish.

### Your first scan, step by step

```bash
recon https://example.com --authorized
```

- `https://example.com` — **your own site**, or one you have written
  permission to test. The tool refuses to run without...
- `--authorized` — ...this flag, which is your explicit confirmation that you
  are allowed to test this target. There is no way around this check; it is
  intentional friction.

What you'll see: a progress line per module as it starts, then a summary line
like `3 info, 2 low, 1 medium` and the path to your report folder. Open
`recon_runs/example.com_<timestamp>/report.html` in a browser — it has a
severity breakdown at the top, a filterable findings table, and a plain-English
explanation and fix recommendation under each one.

If Docker isn't running or isn't installed, you'll see `[~] ports: skipped`
for the Docker-based modules — the scan still completes with whatever modules
could run, it never hard-fails just because one tool is missing.

**A gentler first run** — only the checks that need nothing but Python, which
is a good way to try the tool with zero setup:

```bash
recon example.com -m headers,cors,content,dns --authorized
```

### Using it continuously (CI)

The real value shows up when you run this regularly instead of once. Two
pieces make that practical:

```bash
# Only fail the build when something NEW and at least "high" severity appears.
# The previous run for the same host is used as the baseline automatically.
recon https://example.com --authorized --fail-on-new high
```

Or drop in the reusable GitHub Action:

```yaml
- uses: m0Corut/recon-orchestrator@main
  with:
    target: https://staging.example.com
    modules: "headers,cors,content,dns"
    fail-on-new: "high"
```

`.github/workflows/scan.yml` in this repo is a working example (weekly
schedule + manual trigger) you can copy into your own project.

**Accepted risks.** Some findings are known and deliberately accepted. List
them in `.reconignore.yml` (picked up automatically, or pass
`--suppress-file`). Each entry needs a reason; an optional `expires` date
makes the finding come back, and fail CI again, once the review date passes.
Suppressed findings are left out of counts and `--fail-on*` gates but still
listed in every report under "Suppressed".

```yaml
- rule_id: headers.missing-csp        # glob allowed: "headers.*"
  reason: "CSP rollout tracked in JIRA-123"
  expires: 2027-01-31
- rule_id: ports.notable
  reason: "Redis is firewalled to the VPN"
  fingerprint: 3f2a9c...              # optional: just this one instance
```

**Whole attack surface.** `--discover` adds the `discover` module: it lists
subdomains from Certificate Transparency and subfinder (when available), probes
which in-house ones serve HTTP, and flags dangling CNAMEs. Each live host is a
finding, so the next run reports **new subdomains** through the normal baseline
diff. Discovered hosts are only listed by default; add `--scan-discovered` to
run the other modules against each of them too, and only if you are authorized
for all of them. Hosts that CNAME to a third-party service (Shopify, Heroku, …)
are never probed or scanned, only checked in DNS.

```bash
recon example.com --authorized --discover                    # inventory
recon example.com --authorized --discover --scan-discovered  # inventory + scan each
```

**Notifications.** A scheduled scan is only useful if someone sees it.
`--notify-env RECON_WEBHOOK` reads one or more webhook URLs (comma-separated)
from an environment variable and posts a short message only when there are
NEW findings at `--notify-min-severity` (default `medium`) or above. Slack,
Discord and Telegram (`https://api.telegram.org/bot<TOKEN>/sendMessage?chat_id=<ID>`)
URLs are detected automatically; anything else receives a generic JSON
payload. Messages contain titles and rule ids, never evidence.

### What each module actually checks

| Module | Needs | What it looks for |
|--------|-------|---------------------|
| `headers` | nothing | Missing security headers (HSTS, CSP, X-Frame-Options, …), insecure cookie flags, and server/framework version leaks |
| `cors` | nothing | A CORS policy that reflects an attacker-controlled Origin back, especially combined with credentials |
| `content` | nothing | Accidentally exposed files and paths (`.env`, `.git/config`, backup dumps, debug endpoints) |
| `dns` | `[dns]` extra | Missing or weak SPF/DMARC (email spoofing protection), missing DKIM, missing CAA |
| `ports` | Docker or nmap | Which ports are open and whether a risky service (database, Redis, RDP, …) is reachable from the internet |
| `tls` | Docker or testssl.sh | Outdated TLS versions and weak cipher suites |
| `web` | Docker or nuclei | Thousands of community-maintained signatures for known CVEs, exposed panels, and misconfigurations |
| `authz` | a session cookie/token you provide | Whether pages that should require login are actually reachable without one (read-only — GET/HEAD only, never submits forms) |
| `openapi` | an OpenAPI/Swagger spec | Whether endpoints the spec marks as requiring authentication are reachable without it |
| `mail` | `[dns]` extra | Whether your mail server offers STARTTLS, and whether MTA-STS/TLS-RPT are configured |
| `discover` | nothing (`[dns]` extra recommended; subfinder optional) | Subdomain inventory from Certificate Transparency (crt.sh, Cert Spotter) and subfinder, live web hosts, and dangling CNAMEs that may allow a subdomain takeover. Opt-in via `--discover` |
| `crawl` | katana | Maps the attack surface: endpoints and query parameters, parsing linked JS; `--crawl-headless` drives a browser for single-page apps. Opt-in |
| `cms` | nothing | Detects the CMS (WordPress/Joomla/Drupal) and version, and for WordPress checks REST user enumeration, an exposed debug log, xmlrpc.php and readme. Opt-in (`-m cms`) |
| `idor` | nothing (`--auth-header` recommended) | Heuristic IDOR / broken object-level authorization probe: fetches a neighbouring object id and flags when a distinct object comes back (read-only, GET only). Opt-in (`-m idor`) |
| `csrf` | nothing | State-changing HTML forms without an anti-CSRF token or SameSite session cookie; login forms reported separately. Passive. Opt-in (`-m csrf`) |
| `jsrecon` | nothing | Same-origin JS: hard-coded secrets (masked), outdated/vulnerable libraries (retire.js-style), exposed `.js.map` source maps. Opt-in (`-m jsrecon`) |
| `graphql` | nothing | GraphQL introspection enabled, exposed IDE, debug errors, GET queries — one fixed probe. Opt-in (`-m graphql`) |
| `redirect` | nothing (crawl recommended) | Open redirect on redirect-style params, using a reserved canary; never follows. Opt-in (`-m redirect`) |
| `passive` | nothing | JWT hygiene (decode-only), missing SRI, session id in URL, internal IP/host/path/stack-trace disclosure, mixed content, robots/security.txt. Opt-in (`-m passive`) |
| `hostinject` | nothing | Host-header injection / cache-poisoning **signals** (verify manually); cache-buster on every probe. Opt-in (`-m hostinject`) |

Run `recon modules` any time to see this list with each module's current
description.

### Useful flags at a glance

```bash
--lang tr                     # Turkish report text (default: English)
--format html,json            # choose which report files to write
--scope "api.x.com,*.cdn.x.com"  # allow extra hosts beyond the target itself
--rate 10                     # be gentler on a production target
--jobs 2 / --serial           # limit or disable module parallelism
--config recon.yaml           # load targets/options from a YAML file (recon init to generate one)
--runner native|docker|auto   # how external tools are executed
--analyst anthropic           # optional AI executive summary (opt-in, needs an API key)
--github-issues org/repo      # optional: file a GitHub issue per new finding
--discover [--scan-discovered]  # subdomain inventory (+ scan each live host)
-m cms,idor                    # CMS/WordPress checks and the IDOR probe (opt-in modules)
--idor-url https://s/x/1001    # an id-bearing URL for the idor module to test
-m csrf,jsrecon,graphql,redirect,passive,hostinject  # more opt-in detection modules
--nuclei-profile panels        # nuclei: also run panel/exposure/tech templates (web module)
--suppress-file ignore.yml    # accepted risks (default: .reconignore.yml)
--notify-env RECON_WEBHOOK    # Slack/Discord/Telegram/webhook on NEW findings
--resume                      # continue an interrupted scan; finished modules are reused
--dast                        # nuclei fuzzing on the API spec's GET operations only
```

Full detail on every flag: `recon --help`.

The rate limit adapts on its own: if the target answers `429`/`503`, every
module slows down (and honours `Retry-After`), then speeds back up to `--rate`.
The run says so, because findings may be incomplete.

`--dast` sends real attack payloads, so it is opt-in and deliberately narrow.
If an OpenAPI/Swagger spec is found, nuclei receives a copy that keeps only GET
operations and whose server is rewritten to your target. With no spec, the site
is crawled (katana) and only the discovered GET URLs that carry query
parameters, on the target host, are fuzzed — nothing that changes data. The
`crawl` module (`-m crawl`) runs the same crawl on its own to map the attack
surface. Crawling parses linked JavaScript for endpoints. A JavaScript-heavy single-page
app builds its API calls at runtime, so add `--crawl-headless` to drive a real
headless browser and discover those too (needs Chromium; the all-in-one image
ships it). Headless is slower, so it is opt-in.

**History across runs.** `recon trend` (or `recon trend <output_dir>`) writes
`trend.html`: per host, a stacked bar of findings by severity for each run plus
the same numbers in a table with new/resolved counts. It is a single file with
no external resources, like the report.

**Your own checks.** Another package can add modules without forking this one:

```toml
# pyproject.toml of your package
[project.entry-points."recon_orchestrator.modules"]
mycheck = "my_package.mycheck"   # a module with NAME, NEEDS_DOCKER, run(target, ctx)
```

Plugins appear in `recon modules`, run only when named (`-m headers,mycheck`),
and can never replace a built-in module.

### Architecture (for contributors)

```
recon/
├── cli.py              # argument parsing, config merging, writing reports
├── engine.py           # schedules modules, runs them in parallel, de-duplicates
├── context.py          # ScanContext: typed options shared with every module
├── scope.py            # the allow-list + the redirect-safe HTTP helper
├── ratelimit.py         # the shared, aggregate rate limiter
├── runner.py            # abstracts "run this external tool" over Docker or native binaries
├── diff.py              # fingerprint-based comparison between two runs
├── config.py            # YAML config file loading/validation
├── findings.py          # the Finding/ScanResult data model (rule_id, fingerprint, severity)
├── i18n.py              # English text + Turkish translation catalogue
├── report.py / report_html.py   # Markdown / JSON / SARIF / HTML renderers
├── analyst/             # optional LLM summarization (opt-in, plain HTTP, no SDKs)
├── integrations/github.py       # optional GitHub issue creation
└── modules/             # one file per check; each exposes NAME, NEEDS_DOCKER, run()
```

To add a module: create `recon/modules/<name>.py` exposing `NAME`,
`NEEDS_DOCKER`, and `run(target, ctx) -> list[Finding]`; register it in
`recon/modules/__init__.py`; write finding text in English with a stable
`rule_id`, add the Turkish translation to `recon/i18n.py`; keep any
tool-output parsing in a separate pure function so it's testable without
Docker or the network; add tests under `tests/`.

### Stability, development, license

CLI flags and the `report.json` schema
([docs/report.schema.json](docs/report.schema.json)) are stable from v1.0
onward; breaking changes get a new major version and a CHANGELOG entry.

```bash
pip install -e ".[dev]"
ruff check recon/ tests/ && mypy recon/ && pytest -q
```

Every push/PR runs this same check on Python 3.9–3.13. See
[CONTRIBUTING.md](CONTRIBUTING.md) to add a module or fix a bug.

Licensed under Apache-2.0 — see [LICENSE](LICENSE). Built on top of
[nmap](https://nmap.org), [nuclei](https://github.com/projectdiscovery/nuclei)
and [testssl.sh](https://github.com/drwetter/testssl.sh); this project
orchestrates these tools, it does not replace them.

### ⚠️ Legal

This tool sends real network requests to whatever target you give it. Only
use it against systems you **own** or have **written authorization** to test.
Unauthorized scanning is illegal in most jurisdictions — responsibility is
entirely yours. The `--authorized` flag exists specifically so you cannot run
a scan by accident without consciously confirming this.

---

## Türkçe

### Bu proje ne işe yarıyor?

`recon-orchestrator`, bir web sitesini, API'yi veya alan adını yaygın ve
bilinen güvenlik yanlış yapılandırmalarına karşı kontrol eden bir komut satırı
aracıdır — gerçek sızma testlerinin neredeyse hepsinde çıkan türden sorunlar:
eksik güvenlik başlıkları, internete açık veritabanları, güncel olmayan TLS,
zayıf SPF/DMARC e-posta kayıtları, bilgi sızdıran API endpoint'leri, giriş
gerektirmesi gerekirken gerektirmeyen sayfalar ve benzerleri.

Taramayı sıfırdan **yeniden icat etmez.** Onun yerine, sektörde kanıtlanmış
açık kaynak araçları — [nmap](https://nmap.org) (port taraması),
[nuclei](https://github.com/projectdiscovery/nuclei) (zafiyet şablonları),
[testssl.sh](https://github.com/drwetter/testssl.sh) (TLS denetimi) — ve
kendi hafif Python kontrollerini **orkestre eder**, hepsini tek bir hedefe
karşı çalıştırır, tüm sonuçları tek, tutarlı bir biçimde birleştirir ve sana
elle karşılaştırman gereken altı farklı araç çıktısı yerine tek bir rapor
verir.

**Kimler için:** kendi sitelerini yayına almadan önce, CI'da veya düzenli
aralıklarla ücretsiz ve tekrarlanabilir bir güvenlik kontrolü isteyen
geliştiriciler ve küçük ekipler — ticari bir tarama platformuna para
ödemeden ya da altı ayrı aracı öğrenmeden.

### Araçları kendim çalıştırmak yerine neden bunu kullanayım?

nmap, nuclei ve testssl.sh'ı elle de çalıştırabilirsin — çoğu kişi öyle yapıyor.
Bu proje, o işin hızla sıkıcı hale gelmesi yüzünden var:

- **Tek komut, tek rapor.** Altı terminal penceresi ve altı farklı çıktı
  biçimi yerine, insan için tek bir Markdown/HTML raporu ve makine/CI için
  tek bir JSON/SARIF raporu alırsın.
- **Gürültü azaltma.** Ham araç çıktısı, yanlış-pozitife meyilli ve jargon
  dolu satırlarla doludur. Bu proje her birini önem seviyesi ve öneri içeren
  sade bir bulguya çevirir.
- **Kutudan çıktığı gibi CI uyumlu.** `--fail-on-new high`, build'i yalnızca
  **yeni** bir yüksek önem seviyeli sorun çıktığında durdurur — eski, bilinen,
  kabul edilmiş bir sorun yüzünden her seferinde değil. Bu sayede her pull
  request'te çalıştırmak, sürekli kırmızı build'e boğulmadan gerçekçi olur.
- **Tedarikçi bağımlılığı yok, abonelik yok, LLM maliyeti yok.** Buradaki her
  şey ücretsiz, açık araçlarla çalışır. Opsiyonel bir AI "yönetici özeti"
  vardır ama varsayılan olarak kapalıdır ve araç onsuz da tam olarak
  kullanılabilir.

### Nasıl çalışır?

`recon <hedef> --authorized` çalıştırdığında, sırayla dört şey olur:

1. **Kapsam kilitlenir.** Araç, hedefinin host adını çözer ve bir izin
   listesi (allow-list) kurar (varsayılan: sadece o tek host). Herhangi bir
   modülün yaptığı her HTTP isteği — bir yönlendirmeyi takip etmek dahil —
   önce bu listeye karşı kontrol edilir. Bunun amacı, hedef sitedeki bir
   yönlendirmenin aracı sessizce ilgisiz bir üçüncü taraf alan adını
   yoklamaya başlatmasını kesinlikle engellemektir.

2. **Modüller paralel ve ortak bir hız sınırı altında çalışır.** Her kontrol
   (`headers`, `ports`, `tls`, …) bağımsız bir Python modülüdür. Eşzamanlı
   çalışırlar, böylece yavaş olanlar (nmap, nuclei, testssl — dakikalar
   sürebilir) üst üste binmek yerine örtüşür, bu da toplam tarama süresini
   kabaca yarıya indirir. Gerçek HTTP trafiği gönderen tüm modüller tek bir
   istek-hızı bütçesini (`--rate`, istek/saniye) paylaşır, böylece paralel
   çalışma hedefe binen yükü senin belirlediğinin üzerine çıkarmaz.

3. **Sonuçlar birleştirilir ve tekilleştirilir.** Her bulgu, kelime seçiminden
   veya dilden bağımsız kararlı bir kimlik (`rule_id`) ve bir parmak izi alır.
   İki modül aynı temel sorunu bildirirse, yalnızca bir kez sayılır. Bu aynı
   parmak izi, taramadan taramaya karşılaştırmayı (aşağıda) mümkün kılan şeydir.

4. **Raporlar yazılır.** `recon_runs/<host>_<zaman>/` altına dört dosya
   düşer: okumak için bir Markdown raporu, scriptleme için bir JSON raporu,
   GitHub'ın "Code scanning" arayüzü için bir SARIF dosyası, ve tarayıcıda
   açabileceğin veya e-postaya ekleyebileceğin, dışarıya hiçbir kaynak
   yüklemeyen (tarama sonuçların, sen göndermeyi seçmedikçe makinenden
   çıkmaz) bağımsız bir HTML sayfası.

Aynı host'u sonraki her taramada, araç otomatik olarak son çalıştırmana bakar
ve sana neyin **yeni** olduğunu, neyi zaten bildiğini söyler — böylece
`--fail-on-new` kullanan bir CI hattı yalnızca gerçekten bir şey kötüye
gittiğinde kırmızıya döner.

### Kurulum

**Python 3.9 veya üstü** gerekir. Gerisi, hangi modülleri istediğine bağlı
olarak opsiyoneldir:

| İstediğin... | Gereken |
|---|---|
| Temel kontroller (headers, CORS, içerik keşfi) | Sadece Python + pip |
| DNS/e-posta güvenliği (`dns`) ve mail (`mail`) kontrolleri | `[dns]` extra |
| Port taraması, TLS denetimi, nuclei şablonları (`ports`/`tls`/`web`) | Docker **ya da** araçların native kurulu olması |
| Alt alan adı envanteri (`--discover`) | ek bir şey gerekmez; `[dns]` extra CNAME/takeover kontrollerini, subfinder (Docker ya da native) ek kaynakları ekler |
| API fuzzing (`--dast`) | nuclei (Docker ya da native) ve bir OpenAPI/Swagger şeması |

**Seçenek A — PyPI'dan kur (önerilen):**

```bash
pip install "recon-orchestrator[dns]"            # dns/mail gerekmiyorsa [dns]'i çıkar
pip install "recon-orchestrator[dns]==1.2.1"     # ya da tam sürümü sabitle (ör. CI'da)
pip install -U "recon-orchestrator[dns]"         # mevcut kurulumu güncelle
```

Bu, PATH'ine bir `recon` komutu kurar; hangi sürümün kurulu olduğunu
`recon --version` gösterir.

**Seçenek B — klonla ve kur (kodu okumak ya da değiştirmek için):**

```bash
git clone https://github.com/m0Corut/recon-orchestrator
cd recon-orchestrator
pip install ".[dns]"
```

**Seçenek C — Docker imajı (yerel kurulum sıfır, araçlar dahil):**

Python paketleri kurmak veya tek tek araç imajlarını çekmek istemiyorsan,
hepsi-bir-arada imajı kullan. nmap, nuclei, testssl.sh ve subfinder'ı
container içinde native binary olarak barındırır, yani *sadece* Docker'ın
kendisi gerekir:

```bash
docker run --rm -v "$PWD:/work" ghcr.io/m0corut/recon-orchestrator:1.2.1 \
  https://ornek.com --authorized
```

Taramanın habersizce değişmemesi için `:1.2.1` gibi bir sürüm etiketi kullan;
`:latest` her zaman en yeni sürümü gösterir.

**Araç sürümleri.** Araçlar Docker üzerinden çalıştığında recon sabitlenmiş
imajlar kullanır (nmap 7.98, nuclei v3.11.1, testssl.sh 3.2, subfinder
v2.17.0); böylece aynı recon sürümü hep aynı araçlarla tarar. Native kurduğun
araçlar ise sürümü ne olursa olsun olduğu gibi kullanılır. Varsayılan
`--runner auto` ayarında nmap, nuclei ve testssl.sh'ın üçü de native kuruluysa
onlar, değilse Docker kullanılır. subfinder her iki durumda da isteğe bağlıdır.

**Kurulumunu kontrol etmek:** kurduktan sonra `recon doctor` çalıştır —
tam olarak hangi araçları ve opsiyonel paketleri görebildiğini söyler, böylece
hangi modüllerin gerçekten çalışacağını önceden bilirsin.

**1.0'dan yükseltme.** Hiçbir şey bozulmaz: 1.1'deki yeni özelliklerin hepsi
sen istemedikçe kapalıdır (`--discover`, `--dast`, `--notify-env`,
`--resume`). Tek istisna: tarama yaptığın dizinde bir `.reconignore.yml`
dosyası varsa artık otomatik okunur. Ayrıca taramalar çalışırken
`recon_runs/.partial/` altında küçük bir checkpoint tutar ve bitince siler.

### Adım adım ilk tarama

```bash
recon https://ornek.com --authorized
```

- `https://ornek.com` — **kendi siten**, ya da test etmek için yazılı iznin
  olan bir site. Araç şu olmadan çalışmayı reddeder:
- `--authorized` — bu hedefi test etmeye yetkili olduğunun açık onayı. Bu
  kontrolün etrafından dolanmanın bir yolu yok; bilerek konmuş bir engeldir.

Göreceğin şey: her modül başlarken bir ilerleme satırı, sonra
`3 info, 2 low, 1 medium` gibi bir özet satırı ve rapor klasörünün yolu.
`recon_runs/ornek.com_<zaman>/report.html`'i tarayıcıda aç — üstte önem
dağılımı, filtrelenebilir bir bulgu tablosu, ve her bulgunun altında sade
dilde açıklama ve düzeltme önerisi var.

Docker çalışmıyorsa veya kurulu değilse, Docker tabanlı modüller için
`[~] ports: atlandı` göreceksin — tarama, çalışabilen modüllerle birlikte
yine tamamlanır, sadece bir araç eksik olduğu için asla tamamen durmaz.

**Daha yumuşak bir ilk deneme** — sadece Python dışında hiçbir şey
gerektirmeyen kontroller, aracı sıfır kurulumla denemek için iyi bir yol:

```bash
recon ornek.com -m headers,cors,content,dns --authorized
```

### Sürekli kullanım (CI)

Gerçek değer, bunu bir kere değil düzenli çalıştırdığında ortaya çıkar. Bunu
pratik kılan iki parça var:

```bash
# Build'i yalnızca YENİ ve en az "high" önemde bir şey çıktığında durdur.
# Aynı host için önceki çalıştırma otomatik olarak baz alınır.
recon https://ornek.com --authorized --fail-on-new high
```

Ya da yeniden kullanılabilir GitHub Action'ı ekle:

```yaml
- uses: m0Corut/recon-orchestrator@main
  with:
    target: https://staging.ornek.com
    modules: "headers,cors,content,dns"
    fail-on-new: "high"
```

Bu repodaki `.github/workflows/scan.yml`, kendi projene kopyalayabileceğin
çalışan bir örnektir (haftalık zamanlama + elle tetikleme).

**Kabul edilen riskler.** Bazı bulgular bilinir ve bilerek kabul edilir.
Bunları `.reconignore.yml` dosyasına yaz (otomatik okunur, ya da
`--suppress-file` ver). Her girdi bir gerekçe ister; isteğe bağlı `expires`
tarihi geçince bulgu geri gelir ve CI'ı yeniden kırar. Bastırılan bulgular
sayımlara ve `--fail-on*` kapılarına girmez ama her raporda "Bastırılanlar"
başlığı altında listelenir.

```yaml
- rule_id: headers.missing-csp        # glob kullanılabilir: "headers.*"
  reason: "CSP geçişi JIRA-123'te takip ediliyor"
  expires: 2027-01-31
- rule_id: ports.notable
  reason: "Redis yalnızca VPN'e açık"
  fingerprint: 3f2a9c...              # isteğe bağlı: yalnızca bu örnek
```

**Tüm saldırı yüzeyi.** `--discover`, `discover` modülünü ekler: sertifika
şeffaflığı kayıtlarından ve (varsa) subfinder'dan alt alan adlarını listeler,
sana ait olanlardan hangilerinin HTTP sunduğunu yoklar ve sahipsiz CNAME'leri
işaretler. Her canlı host bir bulgudur, bu yüzden sonraki tarama normal
baseline karşılaştırmasıyla **yeni alt alan adlarını** bildirir. Keşfedilen
host'lar varsayılan olarak yalnızca listelenir; diğer modülleri her birinde de
çalıştırmak için `--scan-discovered` ekle, ama yalnızca hepsi için yetkin
varsa. Üçüncü taraf bir servise (Shopify, Heroku, …) CNAME veren host'lar asla
yoklanmaz ve taranmaz, yalnızca DNS'te kontrol edilir.

```bash
recon ornek.com --authorized --discover                    # envanter
recon ornek.com --authorized --discover --scan-discovered  # envanter + her birini tara
```

**Bildirimler.** Zamanlanmış tarama ancak biri sonucu görürse işe yarar.
`--notify-env RECON_WEBHOOK` bir ortam değişkeninden bir veya daha fazla
webhook adresi okur (virgülle ayrılmış) ve yalnızca `--notify-min-severity`
(varsayılan `medium`) ve üstünde YENİ bulgu varsa kısa bir mesaj gönderir.
Slack, Discord ve Telegram
(`https://api.telegram.org/bot<TOKEN>/sendMessage?chat_id=<ID>`) adresleri
otomatik tanınır; diğerlerine genel bir JSON gönderilir. Mesajlarda başlık ve
rule_id bulunur, kanıt asla bulunmaz.

### Her modül tam olarak ne kontrol ediyor

| Modül | Gereken | Ne arıyor |
|-------|---------|-----------|
| `headers` | hiçbir şey | Eksik güvenlik başlıkları (HSTS, CSP, X-Frame-Options, …), güvensiz cookie bayrakları, sunucu/framework sürüm sızıntıları |
| `cors` | hiçbir şey | Saldırgan kontrolündeki bir Origin'i geri yansıtan CORS politikası, özellikle credentials ile birlikte |
| `content` | hiçbir şey | Yanlışlıkla açık bırakılmış dosya ve yollar (`.env`, `.git/config`, yedek dump'ları, debug endpoint'leri) |
| `dns` | `[dns]` extra | Eksik/zayıf SPF/DMARC (e-posta sahteciliği koruması), eksik DKIM, eksik CAA |
| `ports` | Docker ya da nmap | Hangi portların açık olduğu ve riskli bir servisin (veritabanı, Redis, RDP, …) internetten erişilebilir olup olmadığı |
| `tls` | Docker ya da testssl.sh | Eski TLS sürümleri ve zayıf şifreleyici setleri |
| `web` | Docker ya da nuclei | Bilinen CVE'ler, açık paneller ve yanlış yapılandırmalar için binlerce topluluk imzası |
| `authz` | senin verdiğin bir session cookie/token | Giriş gerektirmesi gereken sayfaların gerçekten girişsiz erişilip erişilemediği (salt-okunur — sadece GET/HEAD, form göndermez) |
| `openapi` | bir OpenAPI/Swagger şeması | Şemanın kimlik doğrulama gerektirdiğini söylediği endpoint'lerin gerçekten kimliksiz erişilip erişilemediği |
| `mail` | `[dns]` extra | Mail sunucunun STARTTLS sunup sunmadığı, MTA-STS/TLS-RPT'nin yapılandırılıp yapılandırılmadığı |
| `discover` | hiçbir şey (`[dns]` extra önerilir; subfinder isteğe bağlı) | Sertifika şeffaflığı (crt.sh, Cert Spotter) ve subfinder ile alt alan adı envanteri, canlı web host'ları ve subdomain takeover'a açık sahipsiz CNAME'ler. `--discover` ile açılır |
| `crawl` | katana | Saldırı yüzeyini haritalar: endpoint ve sorgu parametreleri, bağlı JS'i ayrıştırır; SPA'lar için `--crawl-headless` tarayıcı sürer. Opt-in |
| `cms` | hiçbir şey | CMS'i (WordPress/Joomla/Drupal) ve sürümü tespit eder; WordPress için REST kullanıcı sayımı, açık debug log, xmlrpc.php ve readme kontrolü. Opt-in (`-m cms`) |
| `idor` | hiçbir şey (`--auth-header` önerilir) | Sezgisel IDOR / nesne düzeyi yetki taraması: komşu nesne id'sini getirip farklı bir nesne dönerse işaretler (salt-okunur, yalnızca GET). Opt-in (`-m idor`) |
| `csrf` | hiçbir şey | Anti-CSRF token'ı veya SameSite oturum çerezi olmayan durum değiştiren formlar; giriş formları ayrı raporlanır. Pasif. Opt-in (`-m csrf`) |
| `jsrecon` | hiçbir şey | Same-origin JS: gömülü sırlar (maskeli), eski/açıklı kütüphaneler (retire.js tarzı), açık `.js.map` source map'ler. Opt-in (`-m jsrecon`) |
| `graphql` | hiçbir şey | GraphQL introspection açık, açık IDE, debug hataları, GET sorgusu — tek sabit probe. Opt-in (`-m graphql`) |
| `redirect` | hiçbir şey (crawl önerilir) | Yönlendirme parametrelerinde açık yönlendirme; rezerve canary, asla takip etmez. Opt-in (`-m redirect`) |
| `passive` | hiçbir şey | JWT hijyeni (yalnız decode), eksik SRI, URL'de session id, iç IP/host/yol/stack-trace ifşası, mixed content, robots/security.txt. Opt-in (`-m passive`) |
| `hostinject` | hiçbir şey | Host-header injection / cache poisoning **sinyalleri** (manuel doğrula); her probe'da cache-buster. Opt-in (`-m hostinject`) |

Bu listeyi ve her modülün güncel açıklamasını görmek için istediğin an
`recon modules` çalıştır.

### Göz atılacak kullanışlı bayraklar

```bash
--lang tr                     # Türkçe rapor metni (varsayılan: İngilizce)
--format html,json            # hangi rapor dosyalarının yazılacağını seç
--scope "api.x.com,*.cdn.x.com"  # hedefin dışında ek host'lara izin ver
--rate 10                     # production hedefte daha nazik ol
--jobs 2 / --serial           # modül paralelliğini sınırla veya kapat
--config recon.yaml           # hedefleri/ayarları bir YAML dosyasından oku (üretmek için recon init)
--runner native|docker|auto   # dış araçların nasıl çalıştırılacağı
--analyst anthropic           # opsiyonel AI yönetici özeti (opt-in, API anahtarı gerekir)
--github-issues org/repo      # opsiyonel: her yeni bulgu için bir GitHub issue aç
--discover [--scan-discovered]  # alt alan adı envanteri (+ her canlı host'u tara)
-m cms,idor                    # CMS/WordPress kontrolleri ve IDOR taraması (opt-in modüller)
--idor-url https://s/x/1001    # idor modülünün test edeceği id içeren URL
-m csrf,jsrecon,graphql,redirect,passive,hostinject  # daha fazla opt-in tespit modülü
--nuclei-profile panels        # nuclei: panel/exposure/tech şablonlarını da çalıştır (web)
--suppress-file ignore.yml    # kabul edilen riskler (varsayılan: .reconignore.yml)
--notify-env RECON_WEBHOOK    # YENİ bulguda Slack/Discord/Telegram/webhook
--resume                      # yarıda kalan taramayı sürdür; biten modüller yeniden çalışmaz
--dast                        # nuclei fuzzing, yalnızca API şemasının GET işlemlerinde
```

Her bayrağın tam detayı: `recon --help`.

Hız sınırı kendini ayarlar: hedef `429`/`503` dönerse tüm modüller yavaşlar
(`Retry-After`'a da uyar), sonra yeniden `--rate` değerine çıkar. Sonuçlar
eksik olabileceği için tarama bunu ayrıca bildirir.

`--dast` gerçek saldırı yükleri gönderir; bu yüzden isteğe bağlıdır ve bilerek
dar tutulmuştur: nuclei, API şemasının yalnızca GET işlemlerini içeren (veri
değiştiren hiçbir şey fuzz edilmez) ve sunucu adresi senin hedefine yeniden
yazılmış bir kopyasını alır. Böylece production'ı gösteren bir şema fuzzer'ı
başka yere yönlendiremez.

**Taramalar arası geçmiş.** `recon trend` (veya `recon trend <çıktı_dizini>`)
`trend.html` üretir: her host için, her taramadaki bulguların önem derecesine
göre yığılmış çubuğu ve aynı sayıları yeni/çözülen bilgisiyle bir tabloda
gösterir. Rapor gibi, dış kaynak yüklemeyen tek bir dosyadır.

**Kendi kontrollerin.** Başka bir paket, bu projeyi fork'lamadan modül ekleyebilir:

```toml
# kendi paketinin pyproject.toml dosyası
[project.entry-points."recon_orchestrator.modules"]
mycheck = "my_package.mycheck"   # NAME, NEEDS_DOCKER, run(target, ctx) içeren bir modül
```

Eklentiler `recon modules` listesinde görünür, yalnızca adıyla çağrılınca
çalışır (`-m headers,mycheck`) ve hiçbir zaman yerleşik bir modülün yerine
geçemez.

### Mimari (katkıda bulunanlar için)

```
recon/
├── cli.py              # argüman ayrıştırma, config birleştirme, rapor yazımı
├── engine.py           # modülleri zamanlar, paralel çalıştırır, tekilleştirir
├── context.py          # ScanContext: her modülle paylaşılan tipli ayarlar
├── scope.py            # izin listesi + redirect-güvenli HTTP yardımcısı
├── ratelimit.py         # ortak, toplam hız sınırlayıcı
├── runner.py            # "bu dış aracı çalıştır" işlemini Docker ya da native binary üzerinden soyutlar
├── diff.py              # iki çalıştırma arasında parmak izi tabanlı karşılaştırma
├── config.py            # YAML yapılandırma dosyası yükleme/doğrulama
├── findings.py          # Finding/ScanResult veri modeli (rule_id, fingerprint, önem)
├── i18n.py              # İngilizce metin + Türkçe çeviri kataloğu
├── report.py / report_html.py   # Markdown / JSON / SARIF / HTML üreticiler
├── analyst/             # opsiyonel LLM özeti (opt-in, düz HTTP, SDK yok)
├── integrations/github.py       # opsiyonel GitHub issue oluşturma
└── modules/             # her kontrol için bir dosya; her biri NAME, NEEDS_DOCKER, run() verir
```

Modül eklemek için: `recon/modules/<ad>.py` içinde `NAME`, `NEEDS_DOCKER` ve
`run(target, ctx) -> list[Finding]` sağla; `recon/modules/__init__.py`'ye
kaydet; bulgu metnini İngilizce ve kararlı bir `rule_id` ile yaz, Türkçe
çeviriyi `recon/i18n.py`'ye ekle; araç çıktısı ayrıştırmasını ayrı bir saf
fonksiyonda tut (Docker ya da ağ olmadan test edilebilsin); `tests/` altına
test ekle.

### Kararlılık, geliştirme, lisans

CLI bayrakları ve `report.json` şeması
([docs/report.schema.json](docs/report.schema.json)) v1.0'dan itibaren
kararlıdır; kırıcı değişiklikler yeni bir ana sürümle ve CHANGELOG girdisiyle
gelir.

```bash
pip install -e ".[dev]"
ruff check recon/ tests/ && mypy recon/ && pytest -q
```

Her push/PR bu aynı kontrolü Python 3.9–3.13'te çalıştırır. Bir modül eklemek
veya hata düzeltmek için [CONTRIBUTING.md](CONTRIBUTING.md)'ye bak.

Apache-2.0 altında lisanslıdır — bkz. [LICENSE](LICENSE).
[nmap](https://nmap.org), [nuclei](https://github.com/projectdiscovery/nuclei)
ve [testssl.sh](https://github.com/drwetter/testssl.sh) üzerine kuruludur; bu
proje bu araçları yönetir, yerlerine geçmez.

### ⚠️ Yasal

Bu araç, verdiğin hedefe gerçek ağ istekleri gönderir. Yalnızca **sahibi
olduğun** veya test etmek için **yazılı iznin olan** sistemlerde kullan.
Yetkisiz tarama çoğu ülkede yasa dışıdır — sorumluluk tamamen sana aittir.
`--authorized` bayrağı, bu onayı bilinçli vermeden yanlışlıkla bir tarama
çalıştıramayasın diye özellikle oraya konmuştur.
