One-pass reconnaissance workbench for public domains and IPs.
NetRecon runs a parallel, SSRF-guarded audit against a public target and returns:
| Module | Output |
|---|---|
| DNS | A/AAAA, MX, NS, TXT, PTR · SPF / DMARC posture |
| Web | TLS availability & verification · security header scoring · grade |
| Geo / ASN | City, country, org, ASN from public IP intel |
| Ports | Common-port probe only after DNS TXT ownership proof |
Active TCP probing is ownership-gated on production. Private, loopback, CGNAT, and metadata ranges are rejected at validation time.
┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Browser UI │────▶│ Flask / Vercel │────▶│ recon modules │
│ static JS │◀────│ rate limit + │◀────│ dns · geo · │
│ dark SOC │ │ security hdrs │ │ web · ports │
└─────────────┘ └──────────────────┘ └─────────────────┘
- Backend: Flask, concurrent modules (
ThreadPoolExecutor), ProxyFix - Intel: dnspython, requests, public DNS + IP geolocation APIs
- Optional: Upstash Redis REST for distributed rate limits
- Frontend: Space Grotesk · Plus Jakarta Sans · JetBrains Mono
git clone https://github.com/JoeBuildsThings/NetRecon.git
cd NetRecon
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
pip install -r requirements-dev.txt
python app.py# Health
curl -s https://netrecon.vercel.app/api/health | jq
# Recon (POST JSON)
curl -s -X POST https://netrecon.vercel.app/api/recon \
-H 'Content-Type: application/json' \
-d '{"target":"github.com","include_ports":true}' | jq# Response shape (simplified)
{
"ok": True,
"elapsed_ms": 1234.5,
"partial": False,
"target": {"host": "github.com", "primary_ip": "...", "is_ip": False},
"ownership": {"verified": False, "txt_host": "...", "txt_value": "..."},
"geo": {"asn": "...", "org": "...", "country": "..."},
"dns": {"posture": {"spf_status": "...", "dmarc_policy": "..."}},
"web": {"grade": "A", "score": 92, "tls": {"available": True}},
"ports": {"status": "verification_required", "open_ports": []}
}| Control | Detail |
|---|---|
| SSRF guards | Global-unicast allowlist only — no RFC1918, loopback, link-local, CGNAT, metadata |
| Ownership gate | TXT challenge before active port scans in production |
| Rate limit | 25 req / 60s per client IP (in-memory + optional Upstash) |
| Headers | HSTS, CSP, X-Frame-Options: DENY, Referrer-Policy, Permissions-Policy |
| Data | No persistent user scan DB — history stays in browser localStorage |
pytest tests/ -v
ruff check .GitHub Actions runs ruff + pytest on every push to main (Python 3.11 / 3.12).
| Variable | Purpose |
|---|---|
UPSTASH_REDIS_REST_URL |
Distributed rate-limit store |
UPSTASH_REDIS_REST_TOKEN |
Upstash REST token |
Core operation stays on free tiers — no paid services required.
NetRecon/
├── app.py # Flask entry + /api/recon
├── recon/
│ ├── validator.py # Target normalize + SSRF blocklist
│ ├── dns_intel.py
│ ├── geo_intel.py
│ ├── web_audit.py
│ ├── ownership.py
│ ├── port_scanner.py
│ └── logger.py
├── static/
│ ├── styles.css
│ └── app.js
├── templates/
│ ├── index.html
│ ├── privacy.html
│ └── 404.html
├── tests/
│ └── test_security.py
└── .github/workflows/ci.yml
MIT © Adebiyi Joseph Ayomide / JoeBuildsThings
Authorized testing only. Use NetRecon only on systems you own or have explicit permission to audit.