Skip to content

Commit 8ad9cea

Browse files
committed
feat: all module timeouts now configurable from Settings page
- Added katanaTimeout() and xssTimeout() wrapper functions that read from DB (timeout_katana/timeout_xss) → env → default fallback. - Subdomain katana phase: replaced hardcoded 10*60 with katanaTimeout(). - Subdomain xss-detection phase: replaced hardcoded 20*60 with xssTimeout(). - Domain misconfig phase: replaced hardcoded 1800 with GetTimeout(). - API config response now includes timeout_katana and timeout_xss. - API settings update now persists timeout_katana and timeout_xss to DB. - Settings page now has Katana Crawler and Dalfox XSS timeout inputs. - Now all 6 timeouts (zerodays, nuclei, backup, misconfig, katana, xss) are fully configurable from the dashboard and survive redeployments.
1 parent 9fb2e59 commit 8ad9cea

5 files changed

Lines changed: 42 additions & 6 deletions

File tree

internal/api/ui/pages/settings.js

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,16 @@
111111
<input id="timeout-misconfig-input" type="number" min="0" class="form-control premium-input" value="${escValue(String(cfg.timeout_misconfig ?? 1800))}" />
112112
<span>seconds</span>
113113
</div>
114+
<div class="timeout-field">
115+
<label>🕷️ Katana Crawler</label>
116+
<input id="timeout-katana-input" type="number" min="0" class="form-control premium-input" value="${escValue(String(cfg.timeout_katana ?? 600))}" />
117+
<span>seconds</span>
118+
</div>
119+
<div class="timeout-field">
120+
<label>🐛 Dalfox XSS</label>
121+
<input id="timeout-xss-input" type="number" min="0" class="form-control premium-input" value="${escValue(String(cfg.timeout_xss ?? 1200))}" />
122+
<span>seconds</span>
123+
</div>
114124
</div>
115125
<div style="margin-top: 20px; display: flex; align-items: center; gap: 15px;">
116126
<button class="btn btn-primary" onclick="window.SettingsPage.saveTimeoutSettings()" id="timeout-save-btn">💾 Save All Timeouts</button>
@@ -203,14 +213,18 @@
203213
const nuInput = document.getElementById('timeout-nuclei-input');
204214
const buInput = document.getElementById('timeout-backup-input');
205215
const mcInput = document.getElementById('timeout-misconfig-input');
216+
const kaInput = document.getElementById('timeout-katana-input');
217+
const xsInput = document.getElementById('timeout-xss-input');
206218
const btn = document.getElementById('timeout-save-btn');
207219
const note = document.getElementById('timeout-save-note');
208-
if (!zdInput || !nuInput || !buInput || !mcInput) return;
220+
if (!zdInput || !nuInput || !buInput || !mcInput || !kaInput || !xsInput) return;
209221
const zdVal = parseInt(zdInput.value, 10);
210222
const nuVal = parseInt(nuInput.value, 10);
211223
const buVal = parseInt(buInput.value, 10);
212224
const mcVal = parseInt(mcInput.value, 10);
213-
if ([zdVal, nuVal, buVal, mcVal].some(v => isNaN(v) || v < 0)) {
225+
const kaVal = parseInt(kaInput.value, 10);
226+
const xsVal = parseInt(xsInput.value, 10);
227+
if ([zdVal, nuVal, buVal, mcVal, kaVal, xsVal].some(v => isNaN(v) || v < 0)) {
214228
window.showToast('error', 'Invalid value', 'Timeouts must be 0 or a positive integer.');
215229
return;
216230
}
@@ -225,10 +239,12 @@
225239
timeout_nuclei: nuVal,
226240
timeout_backup: buVal,
227241
timeout_misconfig: mcVal,
242+
timeout_katana: kaVal,
243+
timeout_xss: xsVal,
228244
})
229245
});
230246
if (!res.ok) throw new Error('Failed to update timeout settings');
231-
window.showToast('success', 'Saved!', `Zerodays: ${zdVal}s · Nuclei: ${nuVal}s · Backup: ${buVal}s · Misconfig: ${mcVal}s (0 = unlimited)`);
247+
window.showToast('success', 'Saved!', `Zerodays: ${zdVal}s · Nuclei: ${nuVal}s · Backup: ${buVal}s · Misconfig: ${mcVal}s · Katana: ${kaVal}s · XSS: ${xsVal}s (0 = unlimited)`);
232248
if (note) note.textContent = `✅ Saved to DB at ${new Date().toLocaleTimeString()} — persists across redeployments`;
233249
try { window.state.config = await window.apiFetch('/api/config'); } catch(_) {}
234250
} catch (e) {

internal/api/ui_api.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ func apiConfigHandler(c *gin.Context) {
7171
"timeout_nuclei": utils.GetTimeout("nuclei", 1200),
7272
"timeout_backup": utils.GetTimeout("backup", 600),
7373
"timeout_misconfig": utils.GetTimeout("misconfig", 1800),
74+
"timeout_katana": utils.GetTimeout("katana", 600),
75+
"timeout_xss": utils.GetTimeout("xss", 1200),
7476
// Also include raw env fallbacks for legacy callers.
7577
"timeout_zerodays_env": getIntEnvOr("AUTOAR_TIMEOUT_ZERODAYS", 600),
7678
"timeout_nuclei_env": getIntEnvOr("AUTOAR_TIMEOUT_NUCLEI", 1200),
@@ -90,6 +92,8 @@ type UpdateSettingsBody struct {
9092
TimeoutNuclei *int `json:"timeout_nuclei,omitempty"`
9193
TimeoutBackup *int `json:"timeout_backup,omitempty"`
9294
TimeoutMisconfig *int `json:"timeout_misconfig,omitempty"`
95+
TimeoutKatana *int `json:"timeout_katana,omitempty"`
96+
TimeoutXss *int `json:"timeout_xss,omitempty"`
9397
}
9498

9599
func apiUpdateSettingsHandler(c *gin.Context) {
@@ -125,6 +129,8 @@ func apiUpdateSettingsHandler(c *gin.Context) {
125129
saveTimeout("nuclei", "AUTOAR_TIMEOUT_NUCLEI", body.TimeoutNuclei)
126130
saveTimeout("backup", "AUTOAR_TIMEOUT_BACKUP", body.TimeoutBackup)
127131
saveTimeout("misconfig", "AUTOAR_TIMEOUT_MISCONFIG", body.TimeoutMisconfig)
132+
saveTimeout("katana", "AUTOAR_TIMEOUT_KATANA", body.TimeoutKatana)
133+
saveTimeout("xss", "AUTOAR_TIMEOUT_XSS", body.TimeoutXss)
128134

129135
c.JSON(http.StatusOK, gin.H{"message": "Settings updated successfully", "ok": true})
130136
}

internal/scanner/domain/domain.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ func RunDomain(opts ScanOptions) (*Result, error) {
169169
{"misconfig", "Cloud misconfiguration scan", func() error {
170170
lh := ""; if _, err := os.Stat(liveHostsFile); err == nil { lh = liveHostsFile }
171171
return misconfig.Run(misconfig.Options{Target: domain, Action: "scan", Threads: 150, LiveHostsFile: lh})
172-
}, 1800},
172+
}, utils.GetTimeout("misconfig", 1800)},
173173
}
174174

175175
for _, p := range phases3 {

internal/scanner/subdomain/subdomain.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ func RunSubdomainWithOptions(subdomain string, opts RunOptions) (*Result, error)
269269
// Phase 2.5: Katana (sequential — after URL collection, before deep scanning)
270270
// Needs live hosts + initial URL corpus from Phase 2. Results merged into all-urls.txt
271271
// so GF, reflection, and other Phase 3 tools see the complete URL set.
272-
if err := utils.RunWorkflowPhase("katana", getNextStep(), totalSteps, "[Stage 2.5] Katana crawler", subdomainClean, 10*60, func() error {
272+
if err := utils.RunWorkflowPhase("katana", getNextStep(), totalSteps, "[Stage 2.5] Katana crawler", subdomainClean, katanaTimeout(), func() error {
273273
return urls.RunKatanaPhase(subdomainClean)
274274
}); err != nil {
275275
logger.GetLogger().Infof("[WARN] Katana phase failed: %v", err)
@@ -335,7 +335,7 @@ func RunSubdomainWithOptions(subdomain string, opts RunOptions) (*Result, error)
335335

336336
// Phase 4: Dalfox XSS confirmation (sequential, needs reflection/kxss results from Phase 3)
337337
// Reads kxss-results.txt produced by the reflection phase above.
338-
if err := utils.RunWorkflowPhase("xss-detection", getNextStep(), totalSteps, "[Stage 4] Dalfox XSS confirmation", subdomainClean, 20*60, func() error {
338+
if err := utils.RunWorkflowPhase("xss-detection", getNextStep(), totalSteps, "[Stage 4] Dalfox XSS confirmation", subdomainClean, xssTimeout(), func() error {
339339
return reflection.RunDalfoxPhase(subdomainClean)
340340
}); err != nil {
341341
logger.GetLogger().Infof("[WARN] Dalfox XSS phase failed: %v", err)

internal/scanner/subdomain/timeouts.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,17 @@ func backupTimeout() int {
2525
func nucleiTimeout() int {
2626
return utils.GetTimeout("nuclei", 1200)
2727
}
28+
29+
// katanaTimeout returns the katana crawler phase timeout in seconds.
30+
// Configured via the dashboard Settings page (timeout_katana),
31+
// or AUTOAR_TIMEOUT_KATANA env var. Default: 600s (10 min).
32+
func katanaTimeout() int {
33+
return utils.GetTimeout("katana", 600)
34+
}
35+
36+
// xssTimeout returns the dalfox XSS confirmation phase timeout in seconds.
37+
// Configured via the dashboard Settings page (timeout_xss),
38+
// or AUTOAR_TIMEOUT_XSS env var. Default: 1200s (20 min).
39+
func xssTimeout() int {
40+
return utils.GetTimeout("xss", 1200)
41+
}

0 commit comments

Comments
 (0)