|
| 1 | +{ |
| 2 | + "_metadata": { |
| 3 | + "name": "WAF Edge Recon Triage", |
| 4 | + "description": "Authorized bug bounty workflow that probes live URLs with HTTPx, detects Web Application Firewalls with wafw00f, and writes a prioritized edge-defense recon report.", |
| 5 | + "category": "bug-bounty", |
| 6 | + "tags": ["bug-bounty", "recon", "httpx", "wafw00f", "waf", "edge-defense", "triage"], |
| 7 | + "author": "sentris-team", |
| 8 | + "version": "1.0.0" |
| 9 | + }, |
| 10 | + "manifest": { |
| 11 | + "name": "WAF Edge Recon Triage", |
| 12 | + "description": "Fingerprint live web assets and detect WAF presence for authorized bug bounty targets.", |
| 13 | + "version": "1.0.0", |
| 14 | + "author": "sentris-team", |
| 15 | + "category": "bug-bounty", |
| 16 | + "tags": ["bug-bounty", "recon", "httpx", "wafw00f", "waf", "edge-defense", "triage"], |
| 17 | + "entryPoint": "trigger_1", |
| 18 | + "nodeCount": 5, |
| 19 | + "edgeCount": 8 |
| 20 | + }, |
| 21 | + "graph": { |
| 22 | + "name": "WAF Edge Recon Triage", |
| 23 | + "description": "HTTP probing plus WAF detection for authorized live URLs.", |
| 24 | + "nodes": [ |
| 25 | + { |
| 26 | + "id": "trigger_1", |
| 27 | + "type": "core.workflow.entrypoint", |
| 28 | + "position": { "x": 100, "y": 260 }, |
| 29 | + "data": { |
| 30 | + "label": "Authorized Live URL Input", |
| 31 | + "config": { |
| 32 | + "params": { |
| 33 | + "runtimeInputs": [ |
| 34 | + { |
| 35 | + "id": "liveUrls", |
| 36 | + "label": "Live URLs", |
| 37 | + "type": "array", |
| 38 | + "required": true, |
| 39 | + "description": "Authorized HTTP or HTTPS URLs to probe for WAF and service fingerprinting." |
| 40 | + }, |
| 41 | + { |
| 42 | + "id": "authorizationNotes", |
| 43 | + "label": "Authorization notes", |
| 44 | + "type": "text", |
| 45 | + "required": false, |
| 46 | + "defaultValue": "", |
| 47 | + "description": "Program scope, exclusions, and rate-limit notes." |
| 48 | + } |
| 49 | + ] |
| 50 | + }, |
| 51 | + "inputOverrides": {} |
| 52 | + } |
| 53 | + } |
| 54 | + }, |
| 55 | + { |
| 56 | + "id": "httpx_probe", |
| 57 | + "type": "sentris.httpx.scan", |
| 58 | + "position": { "x": 420, "y": 260 }, |
| 59 | + "data": { |
| 60 | + "label": "Probe Live HTTP Services", |
| 61 | + "config": { |
| 62 | + "params": { |
| 63 | + "threads": 50, |
| 64 | + "followRedirects": true, |
| 65 | + "tlsProbe": true, |
| 66 | + "preferHttps": true |
| 67 | + }, |
| 68 | + "inputOverrides": {} |
| 69 | + } |
| 70 | + } |
| 71 | + }, |
| 72 | + { |
| 73 | + "id": "wafw00f_scan", |
| 74 | + "type": "sentris.wafw00f.run", |
| 75 | + "position": { "x": 740, "y": 260 }, |
| 76 | + "data": { |
| 77 | + "label": "Detect Web Application Firewalls", |
| 78 | + "config": { |
| 79 | + "params": { "findAll": false, "verbose": false }, |
| 80 | + "inputOverrides": {} |
| 81 | + } |
| 82 | + } |
| 83 | + }, |
| 84 | + { |
| 85 | + "id": "rank_waf_recon", |
| 86 | + "type": "core.logic.script", |
| 87 | + "position": { "x": 1060, "y": 260 }, |
| 88 | + "data": { |
| 89 | + "label": "Rank WAF and HTTP Signals", |
| 90 | + "config": { |
| 91 | + "params": { |
| 92 | + "variables": [ |
| 93 | + { "name": "liveUrls", "type": "list-text" }, |
| 94 | + { "name": "authorizationNotes", "type": "string" }, |
| 95 | + { "name": "httpResponses", "type": "list-json" }, |
| 96 | + { "name": "wafDetections", "type": "list-json" }, |
| 97 | + { "name": "detectionCount", "type": "number" } |
| 98 | + ], |
| 99 | + "returns": [{ "name": "report", "type": "json" }], |
| 100 | + "code": "export function script(input) {\n const liveUrls = Array.isArray(input.liveUrls) ? input.liveUrls : [];\n const httpResponses = Array.isArray(input.httpResponses) ? input.httpResponses : [];\n const wafDetections = Array.isArray(input.wafDetections) ? input.wafDetections : [];\n const authorizationNotes = typeof input.authorizationNotes === 'string' && input.authorizationNotes.trim().length > 0 ? input.authorizationNotes.trim() : null;\n const wafByUrl = new Map();\n for (const item of wafDetections) {\n const url = typeof item?.url === 'string' ? item.url : '';\n if (url) wafByUrl.set(url, item);\n }\n const assets = httpResponses.map((resp) => {\n const url = resp?.url || resp?.finalUrl || resp?.input || '';\n const waf = wafByUrl.get(url) || null;\n return {\n url,\n statusCode: resp?.statusCode ?? null,\n title: resp?.title ?? null,\n technologies: Array.isArray(resp?.technologies) ? resp.technologies : [],\n wafDetected: waf?.detected === true,\n firewall: waf?.firewall || null,\n manufacturer: waf?.manufacturer || null\n };\n }).sort((a, b) => Number(b.wafDetected) - Number(a.wafDetected) || Number(b.technologies?.length || 0) - Number(a.technologies?.length || 0));\n const wafBrands = Array.from(new Set(assets.filter((item) => item.wafDetected).map((item) => item.firewall).filter(Boolean)));\n return {\n report: {\n summary: {\n liveUrls: liveUrls.length,\n probedEndpoints: httpResponses.length,\n wafDetections: Number(input.detectionCount || assets.filter((item) => item.wafDetected).length),\n wafBrands,\n interestingWithoutWaf: assets.filter((item) => !item.wafDetected && [200, 401, 403, 500].includes(Number(item.statusCode))).length\n },\n authorizationNotes,\n assets: assets.slice(0, 100),\n nextSteps: [\n 'Treat WAF-detected endpoints as edge-protected before active testing',\n 'Review 401/403 endpoints without WAF signals for auth bypass opportunities',\n 'Stay within authorized scope and rate limits for follow-up testing'\n ]\n }\n };\n}" |
| 101 | + }, |
| 102 | + "inputOverrides": {} |
| 103 | + } |
| 104 | + } |
| 105 | + }, |
| 106 | + { |
| 107 | + "id": "artifact_report", |
| 108 | + "type": "core.artifact.writer", |
| 109 | + "position": { "x": 1380, "y": 260 }, |
| 110 | + "data": { |
| 111 | + "label": "Save WAF Recon Report", |
| 112 | + "config": { |
| 113 | + "params": { |
| 114 | + "fileExtension": ".json", |
| 115 | + "mimeType": "application/json", |
| 116 | + "saveToRunArtifacts": true, |
| 117 | + "publishToArtifactLibrary": false |
| 118 | + }, |
| 119 | + "inputOverrides": { "artifactName": "waf-edge-recon-triage-{{date}}" } |
| 120 | + } |
| 121 | + } |
| 122 | + } |
| 123 | + ], |
| 124 | + "edges": [ |
| 125 | + { |
| 126 | + "id": "trigger_1-httpx_probe-targets", |
| 127 | + "source": "trigger_1", |
| 128 | + "target": "httpx_probe", |
| 129 | + "sourceHandle": "liveUrls", |
| 130 | + "targetHandle": "targets" |
| 131 | + }, |
| 132 | + { |
| 133 | + "id": "trigger_1-wafw00f_scan-targets", |
| 134 | + "source": "trigger_1", |
| 135 | + "target": "wafw00f_scan", |
| 136 | + "sourceHandle": "liveUrls", |
| 137 | + "targetHandle": "targets" |
| 138 | + }, |
| 139 | + { |
| 140 | + "id": "trigger_1-rank_waf_recon-liveUrls", |
| 141 | + "source": "trigger_1", |
| 142 | + "target": "rank_waf_recon", |
| 143 | + "sourceHandle": "liveUrls", |
| 144 | + "targetHandle": "liveUrls" |
| 145 | + }, |
| 146 | + { |
| 147 | + "id": "trigger_1-rank_waf_recon-authorizationNotes", |
| 148 | + "source": "trigger_1", |
| 149 | + "target": "rank_waf_recon", |
| 150 | + "sourceHandle": "authorizationNotes", |
| 151 | + "targetHandle": "authorizationNotes" |
| 152 | + }, |
| 153 | + { |
| 154 | + "id": "httpx_probe-rank_waf_recon-responses", |
| 155 | + "source": "httpx_probe", |
| 156 | + "target": "rank_waf_recon", |
| 157 | + "sourceHandle": "responses", |
| 158 | + "targetHandle": "httpResponses" |
| 159 | + }, |
| 160 | + { |
| 161 | + "id": "wafw00f_scan-rank_waf_recon-detections", |
| 162 | + "source": "wafw00f_scan", |
| 163 | + "target": "rank_waf_recon", |
| 164 | + "sourceHandle": "wafDetections", |
| 165 | + "targetHandle": "wafDetections" |
| 166 | + }, |
| 167 | + { |
| 168 | + "id": "wafw00f_scan-rank_waf_recon-detectionCount", |
| 169 | + "source": "wafw00f_scan", |
| 170 | + "target": "rank_waf_recon", |
| 171 | + "sourceHandle": "detectionCount", |
| 172 | + "targetHandle": "detectionCount" |
| 173 | + }, |
| 174 | + { |
| 175 | + "id": "rank_waf_recon-artifact_report-report", |
| 176 | + "source": "rank_waf_recon", |
| 177 | + "target": "artifact_report", |
| 178 | + "sourceHandle": "report", |
| 179 | + "targetHandle": "content" |
| 180 | + } |
| 181 | + ] |
| 182 | + }, |
| 183 | + "requiredSecrets": [] |
| 184 | +} |
0 commit comments