Dashboard / Documentation
API Docs Try API ↗
Getting Started

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.

Killchain enforcement: Every module has explicit caps on what it will and won't do. Passive modules send zero packets to the target. Active modules stop at detection — they don't exploit. E2E agents limit mutation depth to avoid destructive writes.

Scan Pipeline at a Glance

Phase 1 Reconnaissance — DNS, ports, tech stack, subdomains Phase 2 CVE Intelligence — Shodan CVE lookup, IAM / cloud config Phase 3 AI Surface Analysis — Attack surface model, crown jewel mapping Phase 4 Vulnerability Hunting — Nuclei templates, SSRF, XSS, CORS, smuggling Phase 5 Passive Intelligence — Origin IP, GitHub leaks, JS secrets, Shodan ports Phase 6 OAST Verification — DNS/HTTP callbacks confirm blind vulnerabilities Phase 7 E2E Security Agents — IDOR, mass assignment, business logic, race conditions Phase 8 False Positive Filter — AI re-checks every finding before final report Phase 9 Report Synthesis — Remediation guidance + evidence bundle

Feature

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

1
Open New ScanClick "+ New Scan" in the top-right of the dashboard.
2
Fill in the fieldsEnter the target URL, session cookie, bearer token, out-of-scope paths, and an optional note.
3
Click Save (floppy icon)Type a profile name (defaults to the domain) and confirm. The profile appears in the dropdown immediately.
4
Load it next timeSelect the profile from the dropdown — all fields auto-populate. Then click Start Scan.
Example profile — bug bounty program:
Name: acme-bugbounty  |  Target: https://app.acme.com
Cookie: session=abc123; csrf=xyz
Out-of-scope: /admin/billing, /logout, /gdpr/delete
Note: Use dedicated test account — don't touch billing paths
Where to change this in code Profile logic lives entirely in the browser. To change storage key or add server-side sync:
templates/dashboard.html → functions _getProfiles(), saveScanProfile(), loadScanProfile()
To persist profiles server-side, POST to a new /api/profiles endpoint in main.py.

Feature

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)

1
Log in to the target application using your test account.
2
Open DevTools → F12 (Windows/Linux) or Cmd+Option+I (Mac).
3
Go to Application tab → Cookies (Chrome/Edge) or Storage → Cookies (Firefox). Select the target domain.
4
Copy the relevant cookies in name=value; name2=value2 format. Focus on session-identifying cookies (session_id, auth_token, remember_me, etc.).
5
Paste into SecRecon → New Scan → Authenticated Scan → Session Cookie field.

Getting a Bearer Token

1
Open DevTools → Network tab. Refresh the page or perform any authenticated action.
2
Click any API request (look for XHR/Fetch). Check the Request Headers panel.
3
Find the Authorization header. Copy the value after Bearer — paste only the token, not the word "Bearer".
Two-account IDOR testing: For the most accurate access control testing, provide two session cookies — one for an admin/privileged account and one for a regular user. SecRecon's diff engine compares responses between accounts to detect privilege escalation.
Use dedicated test accounts only. Never run scans against production accounts you don't own or have explicit authorization to test. Check the target's security policy for test account provisioning instructions.
Where to change this in code Backend reads auth fields from the scan request at 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().

Passive

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 runsTool / sourceOutput used for
DNS resolveSystem resolverIP for Shodan/Censys lookup
Port scanNmap (top 1000)Service fingerprint, CVE matching
Tech detectNuclei tech-detect templatesSelects relevant vuln templates in Phase 4
Subdomain enumcrt.sh certificate logs + passive DNSExpands attack surface for later phases
Web crawlKatana (passive + active)Feeds parameterized URLs to SSRF/XSS hunter
Where to change this in code Nmap command: main.py → function run_nmap()
Katana crawl: main.py → function run_katana_crawl() / backend/crawler.py
Subdomain enumeration: main.py → CT-log fetch block (~line 3605)
Subdomain takeover check: backend/subdomain_takeover.py

Passive

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.

Optional API key: Set SHODAN_API_KEY in your environment for CVE lookups and port history. Without a key, this phase uses HackerTarget's free API (lower depth).
Where to change this in code Shodan integration: 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

AI

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.

Required: Set 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.
Where to change this in code AI analysis prompt and logic: backend/research.py
Attack chain reasoning: backend/attack_chain.py
Crown Jewel scoring: main.pycompute_crown_jewel_distance()
Model selection: backend/research.py — change model="gpt-4o" to any OpenAI-compatible model

Active

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.

CheckWhat it testsVerification
SSRFURL parameters, file paths, webhook fields, image URLsOAST DNS/HTTP callback
Reflected XSSAll crawled parameterized URLsNuclei match + DOM check
CORSOrigin header manipulation on API endpointsAccess-Control-Allow-Origin response match
HTTP SmugglingCL.TE and TE.CL desync attemptsResponse timing + body diff
Blind XSSForm fields, headers (X-Forwarded-For, User-Agent)OAST callback with page URL
Path TraversalFile parameter endpointsResponse content match
XXEXML-accepting endpointsOAST DNS callback

Example — SSRF with OAST confirmation

# SecRecon sends this to a parameter like ?url= GET /api/fetch?url=https://abc123.oast.secrecon.dev HTTP/1.1 Host: target.example.com Cookie: session=your-session-cookie # OAST server receives callback from target's IP: [OAST] DNS query: abc123.oast.secrecon.dev from 203.0.113.10 → SSRF CONFIRMED — target fetched attacker-controlled URL
Where to change this in code Nuclei template selection: main.pyrun_nuclei_templates()
SSRF detection: backend/ssrf_hunter.py (or inline in main.py)
CORS scanner: backend/cors_scanner.pyscan_cors_misconfig()
Blind XSS: main.py → blind XSS injection block (~line 3578)
Add new Nuclei templates: place .yaml files in nuclei-templates/ directory

Passive

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).

ModuleWhat it findsAPI key needed?
Origin IP DiscoveryReal server IP behind CDN/WAF — enables firewall bypassNo (uses HackerTarget free)
GitHub Secret ScanAPI keys, tokens, DB passwords in public repos referencing your domainOptional (GITHUB_TOKEN — 5000/hr vs 60/hr)
Shodan / CensysOpen ports, CVEs, exposed services indexed by ShodanSHODAN_API_KEY / CENSYS_API_ID+SECRET
JS Bundle AnalysisHardcoded secrets, internal API endpoints, GraphQL schemas in JS filesNo

Example — Origin IP finding

# Target hides behind Cloudflare — current DNS resolves to CDN target.example.com → 104.16.91.20 (Cloudflare IP) # HackerTarget DNS history shows older A record: target.example.com → 203.0.113.45 (historical) # SecRecon verifies the origin still serves the app: curl -k -H 'Host: target.example.com' https://203.0.113.45/ → HTTP 200 — Title: "Welcome to Target" # Finding: CDN/WAF Bypass — High severity # Attacker can target 203.0.113.45 directly, bypassing WAF
Where to change this in code Origin discovery: backend/origin_discovery.pydiscover_origin_ips()
GitHub scan: backend/github_recon.pyscan_github_for_secrets() — add patterns in _SECRET_PATTERNS
Shodan/Censys: backend/passive_recon.py → add ports to _HIGH_RISK_PORTS
JS analysis: backend/js_analyzer.py → add regex to _ENDPOINT_PATTERNS or _SECRET_PATTERNS
Parallel gather: main.py → "passive intelligence" block (~line 3682)

Verification

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

1
Click "OAST Logs" in the left sidebar of the dashboard.
2
Each callback shows the originating IP, protocol (DNS/HTTP/SMTP), timestamp, and which scan triggered it.
3
DNS callbacks are the most reliable — they pass through firewalls that block HTTP egress.
Self-hosted OAST: Set 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.
Where to change this in code OAST server config: INTERACTSH_SERVER environment variable
Callback polling: main.py_poll_oast_callbacks()
OAST log display: templates/oast_logs.html
Backend OAST API: main.py/api/oast/scan-session/{scan_db_id}

Agents

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.

AgentWhat it testsDetection method
IDOR ProbeNumeric and UUID ID parameters in URLs and query stringsCompares response size + content between ID mutations
Mass AssignmentPOST/PATCH bodies — injects privileged fields (role, admin, is_admin)Detects field reflection or accepted status in response
Business LogicCheckout/payment endpoints — negative prices, zero quantity, coupon bypassDetects unexpected 200 responses to invalid input
Race ConditionState-changing endpoints — sends 10 concurrent requestsAll-success responses indicate TOCTOU window

Example — IDOR detection

# Original request you made (id=142 is yours) GET /api/orders/142 HTTP/1.1 Cookie: session=your-session # Agent mutates to adjacent IDs GET /api/orders/141 HTTP/1.1 → HTTP 200 (body 847 bytes) GET /api/orders/143 HTTP/1.1 → HTTP 200 (body 912 bytes) # Response size ratio within 0.6–1.8 AND contains user-data keywords # → IDOR confirmed: access to other users' orders
Tip: Provide both an Admin cookie and a User cookie for maximum IDOR detection. The diff engine compares responses between privilege levels, catching vertical privilege escalation as well as horizontal IDOR.
Where to change this in code All 4 agents: backend/e2e_agents.py
IDOR ID mutation logic: backend/e2e_agents.py_mutate_id() and _extract_id_params()
Mass assignment field list: backend/e2e_agents.py_PRIV_FIELDS list
Business logic path filter: backend/e2e_agents.py_BL_PATH_PATTERN
Race condition concurrency: backend/e2e_agents.pyrun_race_condition() (_CONCURRENT = 10)
Agent timeout in pipeline: main.py → E2E agent stage (timeout=120)

Output

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.

FieldDescription
severitycritical / high / medium / low / info — aligned to CVSS ranges
confidence_score0–100 — ≥90 = verified, 70–89 = probable, <70 = possible
oast_verifiedtrue if an out-of-band callback confirmed the finding
owasp_categoryOWASP Top 10 2021 mapping (e.g. A01:2021 - Broken Access Control)
evidence.curl_commandExact curl command to reproduce the finding
evidence.requestFull HTTP request that triggered the finding
evidence.response_bodyFirst 3000 bytes of the response
remediationStep-by-step fix guidance specific to the finding type
agentSet 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.

Where to change this in code Finding card rendering: static/js/app.jsrenderRiskCards()
Filter logic: static/js/app.js_applyFindingsFilter() and filterFindings()
Finding drawer (detail view): templates/dashboard.html#findingDrawer section
Client-side enrichment: static/js/app.jsclientEnrichAllFindings()

Output

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:

1
PDF Report — Full executive + technical report. Navigate to My Scans, click the scan, then "Download Report".
2
Evidence Bundle — ZIP containing all curl commands, raw requests, and response bodies for each finding. Use /api/scan/{scan_id}/evidence-bundle.
3
Bug Bounty Export — Formats findings as a Markdown report formatted for platform submission. Use /api/scan/{scan_id}/bounty-export.
4
Compliance Report — Maps findings to SOC 2, ISO 27001, and PCI-DSS controls. Use /api/scan/{scan_id}/compliance-report.
Where to change this in code PDF generation: main.py/api/scan/{scan_id}/report endpoint
Evidence bundle: main.py/api/scan/{scan_id}/evidence-bundle
Report template styling: backend/report_generator.py (if exists) or inline in main.py

API

REST API

Trigger scans programmatically, poll results, and integrate SecRecon into CI/CD pipelines using your API key.

Generate an API Key

1
Go to Dashboard → Settings → Agents → Register Agent.
2
Give it a name (e.g. "CI pipeline") and copy the generated key.

Start a scan

POST /api/v1/scan X-API-Key: your-api-key Content-Type: application/json { "target": "https://staging.example.com", "scan_mode": "full" }

Poll for results

GET /api/scan/{scan_id}/status X-API-Key: your-api-key # Response when complete: { "status": "complete", "risk_score": "C", "vulnerabilities_found": 7, "findings": [...] }
Where to change this in code API v1 endpoint: 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_LIMITS
Full API docs: /api-docs

Config

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:

FormatExampleWhat it excludes
Path prefix/admin/billingAll URLs starting with /admin/billing
Wildcard domain*.cdn.example.comAll subdomains matching pattern
Exact domainstatic.example.comOnly that subdomain
IP or CIDR10.0.0.0/8All IPs in that range
Example for a SaaS bug bounty program:
/admin/billing, /logout, /gdpr/delete, *.partner.example.com, 192.168.0.0/16
Where to change this in code Scope parsing: main.pyparse_oos_config()
Finding filter: main.pyfilter_findings_by_scope()
Subdomain scope guard: main.pyfilter_subdomains_by_scope()

Config

Environment Variables

All secrets and third-party API keys are configured via environment variables — never hardcoded.

VariableRequiredPurpose
AI_INTEGRATIONS_OPENAI_API_KEYRecommendedAI surface analysis, attack chain reasoning, false-positive filter
ANTHROPIC_API_KEYOptionalAlternate AI model (Claude) for research phase
SHODAN_API_KEYOptionalCVE lookups, port history, host intelligence
CENSYS_API_IDOptionalCensys host/certificate data (use with CENSYS_API_SECRET)
CENSYS_API_SECRETOptionalRequired alongside CENSYS_API_ID
GITHUB_TOKENOptionalGitHub code search — 5000 req/hr vs 60 req/hr unauthenticated
INTERACTSH_SERVEROptionalSelf-hosted OAST server domain (e.g. oast.yourdomain.com)
SECRECON_BASE_URLOptionalPublic URL of this SecRecon instance (for blind XSS callbacks)
DATABASE_URLRequiredPostgreSQL connection string
CLERK_SECRET_KEYRequiredAuth provider secret key
Where to change this in code All env reads are via 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