The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "ReconDash - Web Recon Workflow",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "recon-trigger",
"responseMode": "lastNode",
"options": {}
},
"id": "node_webhook",
"name": "Webhook Trigger",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
250,
300
],
"notes": "Entry point \u2014 receives {target_url} from the Python backend or directly from UI."
},
{
"parameters": {
"functionCode": "// \u2500\u2500 Validate input URL \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst body = items[0].json.body || items[0].json;\nconst targetUrl = (body.target_url || '').trim();\n\nif (!targetUrl.match(/^https?:\\/\\//i)) {\n throw new Error('Invalid URL: must start with http:// or https://');\n}\n\nconst { hostname } = new URL(targetUrl);\nconst blocked = ['localhost', '127.', '0.0.0.0', '192.168.', '10.', '172.16.'];\nfor (const b of blocked) {\n if (hostname.startsWith(b)) {\n throw new Error(`Blocked: ${hostname} is a private/local address.`);\n }\n}\n\nreturn [{ json: { target_url: targetUrl, hostname, timestamp: new Date().toISOString() } }];\n"
},
"id": "node_validate",
"name": "Validate URL",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
450,
300
]
},
{
"parameters": {
"url": "http://127.0.0.1:8000/scan/start",
"method": "POST",
"bodyParametersUi": {
"parameter": []
},
"sendBody": true,
"bodyContentType": "json",
"jsonBody": "={{ JSON.stringify({ target_url: $json.target_url }) }}",
"options": {
"timeout": 30000
}
},
"id": "node_recon",
"name": "Start Recon (Python API)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
650,
300
],
"notes": "Calls FastAPI /scan/start \u2192 resolves IP and gets Ollama assessment."
},
{
"parameters": {
"functionCode": "// \u2500\u2500 Check AI assessment for recommendation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst data = items[0].json;\nconst assessment = (data.ai_assessment || '').toLowerCase();\n\n// Determine if AI recommends scanning\nconst recommended = !assessment.includes('caution') && !assessment.includes('not recommended');\n\nreturn [{\n json: {\n ...data,\n ai_recommends_scan: recommended,\n decision_reason: recommended ? 'AI approved' : 'AI flagged caution'\n }\n}];\n"
},
"id": "node_ai_decision",
"name": "AI Decision Logic",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
850,
300
]
},
{
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{ $json.ai_recommends_scan }}",
"value2": true
}
]
}
},
"id": "node_if_proceed",
"name": "Should Run Nikto?",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
1050,
300
],
"notes": "True = AI says proceed. False = AI flagged caution."
},
{
"parameters": {
"url": "http://127.0.0.1:8000/scan/confirm",
"method": "POST",
"sendBody": true,
"bodyContentType": "json",
"jsonBody": "={{ JSON.stringify({ scan_id: $json.scan_id, confirmed: true }) }}",
"options": {}
},
"id": "node_confirm_yes",
"name": "Confirm \u2192 Run Nikto",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
1250,
200
],
"notes": "Triggers Nikto scan via FastAPI /scan/confirm"
},
{
"parameters": {
"functionCode": "// \u2500\u2500 Poll until scan completes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Note: In real n8n, use a Wait node + recursive webhook for true async.\n// This example does a simple pass-through; polling is done by the frontend.\nconst data = items[0].json;\nreturn [{ json: { ...data, n8n_action: 'scan_triggered', message: 'Nikto started. Frontend will poll /scan/status.' } }];\n"
},
"id": "node_wait_result",
"name": "Await Result (pass-through)",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
1450,
200
]
},
{
"parameters": {
"functionCode": "const data = items[0].json;\nreturn [{ json: { ...data, n8n_action: 'scan_skipped', message: 'AI flagged caution. Scan not triggered.' } }];\n"
},
"id": "node_skip",
"name": "Skip Scan (AI Caution)",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
1250,
420
]
},
{
"parameters": {
"url": "http://127.0.0.1:8000/scan/result/={{ $json.scan_id }}",
"method": "GET",
"options": {}
},
"id": "node_fetch_results",
"name": "Fetch Final Results",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [
1650,
200
],
"notes": "After scan completes, fetch parsed results from API."
},
{
"parameters": {
"functionCode": "// \u2500\u2500 Store result to JSON file (simple persistence) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// In production: store to PostgreSQL, MongoDB, or Elasticsearch.\nconst data = items[0].json;\nconst summary = {\n scan_id: data.scan_id,\n target: data.target_url,\n ip: data.ip_address,\n findings_count: (data.findings || []).length,\n high_count: (data.findings || []).filter(f => f.severity === 'HIGH').length,\n completed_at: data.completed_at,\n summary: data.summary\n};\nconsole.log('[ReconDash n8n] Scan stored:', JSON.stringify(summary));\nreturn [{ json: { ...data, stored: true, n8n_summary: summary } }];\n"
},
"id": "node_store",
"name": "Store Result",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
1850,
200
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify($json) }}"
},
"id": "node_respond",
"name": "Return Response",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
2050,
300
]
}
],
"connections": {
"Webhook Trigger": {
"main": [
[
{
"node": "Validate URL",
"type": "main",
"index": 0
}
]
]
},
"Validate URL": {
"main": [
[
{
"node": "Start Recon (Python API)",
"type": "main",
"index": 0
}
]
]
},
"Start Recon (Python API)": {
"main": [
[
{
"node": "AI Decision Logic",
"type": "main",
"index": 0
}
]
]
},
"AI Decision Logic": {
"main": [
[
{
"node": "Should Run Nikto?",
"type": "main",
"index": 0
}
]
]
},
"Should Run Nikto?": {
"main": [
[
{
"node": "Confirm \u2192 Run Nikto",
"type": "main",
"index": 0
}
],
[
{
"node": "Skip Scan (AI Caution)",
"type": "main",
"index": 0
}
]
]
},
"Confirm \u2192 Run Nikto": {
"main": [
[
{
"node": "Await Result (pass-through)",
"type": "main",
"index": 0
}
]
]
},
"Await Result (pass-through)": {
"main": [
[
{
"node": "Fetch Final Results",
"type": "main",
"index": 0
}
]
]
},
"Fetch Final Results": {
"main": [
[
{
"node": "Store Result",
"type": "main",
"index": 0
}
]
]
},
"Store Result": {
"main": [
[
{
"node": "Return Response",
"type": "main",
"index": 0
}
]
]
},
"Skip Scan (AI Caution)": {
"main": [
[
{
"node": "Return Response",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {},
"id": "recondash-workflow-v1",
"tags": [
"security",
"recon",
"local"
]
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
ReconDash - Web Recon Workflow. Uses httpRequest. Webhook trigger; 11 nodes.
Source: https://github.com/SarthakShende/ReconDash-Local-AI-Powered-Web-Reconnaissance-Dashboard/blob/ff97319048abc05db5b3d00a6e38bd113290e7da/n8n/recon-workflow.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This n8n template provides enterprise-level version control for your workflows using GitHub integration. Stop losing hours to broken workflows and manual exports – get proper commit history, visual di
This flow creates dummy files for every item added in your *Arrs (Radarr/Sonarr) with the tag .
eek-Go v2 (Batch-Then-Review). Uses httpRequest. Webhook trigger; 75 nodes.
This workflow receives webhook requests from a content calendar and uses the X API v2 to publish text posts, threads, image/video posts, and polls, as well as delete existing posts and run a credentia
This workflow acts as a central API gateway for all technical indicator agents in the Binance Spot Market Quant AI system. It listens for incoming webhook requests and dynamically routes them to the c