SecRecon Docs
End-to-end security scanning platform — passive recon to authenticated exploit chaining, all in one pipeline.
SecRecon runs a multi-phase scan pipeline against a target domain. Each phase adds context for the next, so the final findings list represents what an attacker could realistically chain together — not just a list of open ports.
A full scan takes 5–20 minutes depending on the target's surface area. Phases run concurrently where safe to do so.
Scan Pipeline at a Glance
Scan Profiles
Save and reuse named configurations — target, credentials, out-of-scope rules, and notes — so you don't re-enter them every scan.
Scan Profiles are stored in your browser's localStorage. They never leave your device — credentials are not sent to SecRecon's servers until you click "Start Scan".
How to create a profile
Name:
acme-bugbounty | Target: https://app.acme.comCookie:
session=abc123; csrf=xyzOut-of-scope:
/admin/billing, /logout, /gdpr/deleteNote:
Use dedicated test account — don't touch billing paths
templates/dashboard.html → functions _getProfiles(), saveScanProfile(), loadScanProfile()To persist profiles server-side, POST to a new
/api/profiles endpoint in main.py.
Authenticated Scanning
Provide session credentials so SecRecon can scan behind login walls — finding IDOR, access control gaps, and business logic bugs only visible when logged in.
Without credentials, SecRecon scans the public attack surface only. With credentials, the crawler, nuclei templates, CORS checks, SSRF injections, blind XSS, and all E2E agents all operate with your session — dramatically increasing coverage.
Getting your session cookie (browser DevTools)
name=value; name2=value2 format. Focus on session-identifying cookies (session_id, auth_token, remember_me, etc.).Getting a Bearer Token
Bearer — paste only the token, not the word "Bearer".main.py:2054–2056:auth_admin_cookie = data.get("auth_admin_cookie", "")auth_user_cookie = data.get("auth_user_cookie", "")auth_bearer_token = data.get("auth_bearer_token", "")These are forwarded to every scanner module. To add a second user cookie field in the UI, add it to the modal in
templates/dashboard.html and map it to auth_user_cookie in startQuickScan().
Phase 1 — Reconnaissance
DNS resolution, port scanning via Nmap, technology fingerprinting via Nuclei, and subdomain enumeration — all before any vulnerability tests run.
Recon builds the target's asset inventory. Subdomains, open ports, detected frameworks (Nginx version, CMS, CDN provider), and cloud provider detection all feed into the AI surface analysis in Phase 3.
| What runs | Tool / source | Output used for |
|---|---|---|
| DNS resolve | System resolver | IP for Shodan/Censys lookup |
| Port scan | Nmap (top 1000) | Service fingerprint, CVE matching |
| Tech detect | Nuclei tech-detect templates | Selects relevant vuln templates in Phase 4 |
| Subdomain enum | crt.sh certificate logs + passive DNS | Expands attack surface for later phases |
| Web crawl | Katana (passive + active) | Feeds parameterized URLs to SSRF/XSS hunter |
main.py → function run_nmap()Katana crawl:
main.py → function run_katana_crawl() / backend/crawler.pySubdomain enumeration:
main.py → CT-log fetch block (~line 3605)Subdomain takeover check:
backend/subdomain_takeover.py
Phase 2 — CVE Intelligence
Matches detected software versions against known CVEs using Shodan's vulnerability database, NVD, and cloud IAM config checks.
If Nmap or Nuclei detect a software version (e.g. Apache 2.4.49, OpenSSH 7.4), SecRecon cross-references it against CVE databases. Critical-severity CVEs get promoted to the top of the findings list.
Cloud metadata checks look for exposed AWS IMDS endpoints, GCP metadata service, and Azure IMDS — a common attack path when SSRF is present.
SHODAN_API_KEY in your environment for CVE lookups and port history. Without a key, this phase uses HackerTarget's free API (lower depth).
backend/passive_recon.py → _shodan_host_lookup()CVE classification:
backend/passive_recon.py → _classify_shodan_data()Cloud metadata checks:
main.py → CVE Intel phase block
Phase 3 — AI Surface Analysis
An AI model ingests recon data to build an attack surface model — identifying authentication boundaries, API patterns, and "crown jewels" (paths closest to critical data).
The AI uses the technology stack, subdomain list, and open services to reason about what an attacker would prioritize. It outputs a ranked list of high-value attack paths and selects the Nuclei template categories most likely to yield findings.
Crown Jewel Distance measures how many hops separate a finding from your most critical assets (admin panel, database credentials, cloud keys). A single SSRF to the cloud metadata endpoint scores lower distance than a reflected XSS on a marketing page.
AI_INTEGRATIONS_OPENAI_API_KEY (or OPENAI_API_KEY as fallback) to enable this phase. Without it, the scan skips AI analysis and uses default template selection.
backend/research.pyAttack chain reasoning:
backend/attack_chain.pyCrown Jewel scoring:
main.py → compute_crown_jewel_distance()Model selection:
backend/research.py — change model="gpt-4o" to any OpenAI-compatible model
Phase 4 — Vulnerability Hunting
Active probing with Nuclei templates, SSRF detection, CORS misconfiguration scanning, HTTP request smuggling, blind XSS injection, and GraphQL endpoint probing.
This is the heaviest phase. Nuclei templates are selected based on Phase 3 AI analysis — only templates relevant to the detected stack run, avoiding noise from irrelevant checks.
| Check | What it tests | Verification |
|---|---|---|
| SSRF | URL parameters, file paths, webhook fields, image URLs | OAST DNS/HTTP callback |
| Reflected XSS | All crawled parameterized URLs | Nuclei match + DOM check |
| CORS | Origin header manipulation on API endpoints | Access-Control-Allow-Origin response match |
| HTTP Smuggling | CL.TE and TE.CL desync attempts | Response timing + body diff |
| Blind XSS | Form fields, headers (X-Forwarded-For, User-Agent) | OAST callback with page URL |
| Path Traversal | File parameter endpoints | Response content match |
| XXE | XML-accepting endpoints | OAST DNS callback |
Example — SSRF with OAST confirmation
main.py → run_nuclei_templates()SSRF detection:
backend/ssrf_hunter.py (or inline in main.py)CORS scanner:
backend/cors_scanner.py → scan_cors_misconfig()Blind XSS:
main.py → blind XSS injection block (~line 3578)Add new Nuclei templates: place
.yaml files in nuclei-templates/ directory
Phase 5 — Passive Intelligence
Four passive modules run in parallel: origin IP discovery, GitHub public secret scanning, Shodan/Censys port intelligence, and JavaScript bundle analysis.
These modules make zero contact with the target. All data comes from public third-party sources. They run concurrently (~60s total instead of ~240s sequential).
| Module | What it finds | API key needed? |
|---|---|---|
| Origin IP Discovery | Real server IP behind CDN/WAF — enables firewall bypass | No (uses HackerTarget free) |
| GitHub Secret Scan | API keys, tokens, DB passwords in public repos referencing your domain | Optional (GITHUB_TOKEN — 5000/hr vs 60/hr) |
| Shodan / Censys | Open ports, CVEs, exposed services indexed by Shodan | SHODAN_API_KEY / CENSYS_API_ID+SECRET |
| JS Bundle Analysis | Hardcoded secrets, internal API endpoints, GraphQL schemas in JS files | No |
Example — Origin IP finding
backend/origin_discovery.py → discover_origin_ips()GitHub scan:
backend/github_recon.py → scan_github_for_secrets() — add patterns in _SECRET_PATTERNSShodan/Censys:
backend/passive_recon.py → add ports to _HIGH_RISK_PORTSJS analysis:
backend/js_analyzer.py → add regex to _ENDPOINT_PATTERNS or _SECRET_PATTERNSParallel gather:
main.py → "passive intelligence" block (~line 3682)
Phase 6 — OAST Verification
Out-of-Band Application Security Testing — a callback server that proves blind vulnerabilities with cryptographic evidence.
OAST works by injecting a unique subdomain URL (e.g. abc123.oast.secrecon.dev) into vulnerable parameters. If the target server fetches that URL, the OAST server records the DNS query or HTTP request — proving the vulnerability without relying on response reflection.
This confirms vulnerabilities that would otherwise be invisible: blind SSRF, blind XXE, blind command injection, DNS rebinding.
View OAST callbacks
INTERACTSH_SERVER=oast.yourdomain.com to route all callbacks through your own interactsh server. This keeps callback data private and avoids rate limits on the public interactsh.com service.
INTERACTSH_SERVER environment variableCallback polling:
main.py → _poll_oast_callbacks()OAST log display:
templates/oast_logs.htmlBackend OAST API:
main.py → /api/oast/scan-session/{scan_db_id}
Phase 7 — E2E Security Agents
Four autonomous agents test application logic using discovered endpoints and your session credentials — finding IDOR, mass assignment, business logic flaws, and race conditions.
E2E agents require authenticated sessions to be meaningful. They operate on the endpoints discovered by the crawler and JS analyzer, so more crawl coverage = more agent coverage.
All agents respect a killchain limit — they detect and report, never modify production data or trigger bulk operations.
| Agent | What it tests | Detection method |
|---|---|---|
| IDOR Probe | Numeric and UUID ID parameters in URLs and query strings | Compares response size + content between ID mutations |
| Mass Assignment | POST/PATCH bodies — injects privileged fields (role, admin, is_admin) | Detects field reflection or accepted status in response |
| Business Logic | Checkout/payment endpoints — negative prices, zero quantity, coupon bypass | Detects unexpected 200 responses to invalid input |
| Race Condition | State-changing endpoints — sends 10 concurrent requests | All-success responses indicate TOCTOU window |
Example — IDOR detection
backend/e2e_agents.pyIDOR ID mutation logic:
backend/e2e_agents.py → _mutate_id() and _extract_id_params()Mass assignment field list:
backend/e2e_agents.py → _PRIV_FIELDS listBusiness logic path filter:
backend/e2e_agents.py → _BL_PATH_PATTERNRace condition concurrency:
backend/e2e_agents.py → run_race_condition() (_CONCURRENT = 10)Agent timeout in pipeline:
main.py → E2E agent stage (timeout=120)
Understanding Findings
Each finding is a structured object with severity, OWASP category, CVSS score, evidence, and remediation — ready for bug bounty reports or internal tickets.
| Field | Description |
|---|---|
| severity | critical / high / medium / low / info — aligned to CVSS ranges |
| confidence_score | 0–100 — ≥90 = verified, 70–89 = probable, <70 = possible |
| oast_verified | true if an out-of-band callback confirmed the finding |
| owasp_category | OWASP Top 10 2021 mapping (e.g. A01:2021 - Broken Access Control) |
| evidence.curl_command | Exact curl command to reproduce the finding |
| evidence.request | Full HTTP request that triggered the finding |
| evidence.response_body | First 3000 bytes of the response |
| remediation | Step-by-step fix guidance specific to the finding type |
| agent | Set for E2E agent findings — identifies which agent found it |
Filter bar
The filter bar above findings lets you narrow by category: All, E2E Agents (purple-bordered cards), IDOR, Secrets, and Network. Counts update live as findings load.
static/js/app.js → renderRiskCards()Filter logic:
static/js/app.js → _applyFindingsFilter() and filterFindings()Finding drawer (detail view):
templates/dashboard.html → #findingDrawer sectionClient-side enrichment:
static/js/app.js → clientEnrichAllFindings()
Reports & Export
Generate PDF security audit reports, compliance reports, and evidence bundles for bug bounty submissions.
After a scan completes, the report is available immediately. From the scan results screen:
/api/scan/{scan_id}/evidence-bundle./api/scan/{scan_id}/bounty-export./api/scan/{scan_id}/compliance-report.main.py → /api/scan/{scan_id}/report endpointEvidence bundle:
main.py → /api/scan/{scan_id}/evidence-bundleReport template styling:
backend/report_generator.py (if exists) or inline in main.py
REST API
Trigger scans programmatically, poll results, and integrate SecRecon into CI/CD pipelines using your API key.
Generate an API Key
Start a scan
Poll for results
main.py → @app.post("/api/v1/scan") (~line 1093)Auth middleware:
main.py → _resolve_api_key_user()Rate limiting:
main.py → _check_ip_rate_limit() and _IP_RATE_LIMITSFull API docs: /api-docs
Out-of-Scope Rules
Prevent SecRecon from testing paths, domains, or IP ranges that the target program marks as out of scope.
Enter out-of-scope rules in the scan modal (comma-separated). Supported formats:
| Format | Example | What it excludes |
|---|---|---|
| Path prefix | /admin/billing | All URLs starting with /admin/billing |
| Wildcard domain | *.cdn.example.com | All subdomains matching pattern |
| Exact domain | static.example.com | Only that subdomain |
| IP or CIDR | 10.0.0.0/8 | All IPs in that range |
/admin/billing, /logout, /gdpr/delete, *.partner.example.com, 192.168.0.0/16
main.py → parse_oos_config()Finding filter:
main.py → filter_findings_by_scope()Subdomain scope guard:
main.py → filter_subdomains_by_scope()
Environment Variables
All secrets and third-party API keys are configured via environment variables — never hardcoded.
| Variable | Required | Purpose |
|---|---|---|
| AI_INTEGRATIONS_OPENAI_API_KEY | Recommended | AI surface analysis, attack chain reasoning, false-positive filter |
| ANTHROPIC_API_KEY | Optional | Alternate AI model (Claude) for research phase |
| SHODAN_API_KEY | Optional | CVE lookups, port history, host intelligence |
| CENSYS_API_ID | Optional | Censys host/certificate data (use with CENSYS_API_SECRET) |
| CENSYS_API_SECRET | Optional | Required alongside CENSYS_API_ID |
| GITHUB_TOKEN | Optional | GitHub code search — 5000 req/hr vs 60 req/hr unauthenticated |
| INTERACTSH_SERVER | Optional | Self-hosted OAST server domain (e.g. oast.yourdomain.com) |
| SECRECON_BASE_URL | Optional | Public URL of this SecRecon instance (for blind XSS callbacks) |
| DATABASE_URL | Required | PostgreSQL connection string |
| CLERK_SECRET_KEY | Required | Auth provider secret key |
os.environ.get("VAR_NAME", "") scattered in main.py and backend modules.To add a new env var: add it to your platform's Secrets/Environment panel, then read it in the relevant module.
AI key fallback chain:
main.py line 2054 area and backend/research.py, backend/attack_chain.py