A domain. Default scanme.nmap.org. Archived URLs for it and its subdomains are pulled in.
How It Works
Archived URLs are cleaned down to ones that reflect input.
Each parameter is tested for reflected and DOM XSS.
Results
A PDF of XSS findings, plus the URLs that were tested.
Also writes report.json.
Overview
Cross-site scripting survives because the parameter that reflects input is rarely
the one anybody documented. It is on a page shipped three years ago, reachable
from a link in an old email, still wired to the same template. Testing the
application you know about misses it every time.
This works from the application's history instead. You get the archived URL set
for a domain, narrowed to the parameters that historically carry reflected
values, then fuzzed and confirmed, so what lands in the report is a payload that
actually executed rather than a parameter that looks suspicious. Running it after
each release turns it into
continuous security testing, because
the regression you care about is a fix that quietly came undone.
The fuzzing step is distributed, which is what makes a large URL set finish in
reasonable time.
urldedupe collapses URLs that differ only by parameter
value.
gf keeps the ones whose parameters match known XSS patterns.
qsreplace substitutes a probe value into each parameter.
The candidate list is capped so a large archive cannot run away.
dalfox fuzzes each candidate across the fleet and verifies
which payloads execute.
Confirmed findings are written to a PDF report.
Inputs
Target domain. One domain. You do not supply a URL list, because the whole
candidate set is built from the domain's own archived history.
Parameter patterns.gf decides which parameters are worth testing
using its XSS pattern set. Left alone, that default is what keeps the fuzzer off
parameters that have never reflected anything.
Candidate cap. The list handed to the fuzzer is capped before it runs, so a domain
with a large archive cannot turn one run into an open-ended fuzz. Widen it only when
you know the scope can take it.
Outputs
A PDF report. Confirmed findings only, each with the parameter, the payload, and
the evidence that it executed. A parameter that reflects without executing does not
appear, which is what keeps the file short enough to act on.
A filtered candidate list. The archived URLs that survived deduplication and
pattern matching, which is a reusable target set for other parameter testing.
The raw archived URL set. Everything the archive collection step returned for the
domain, before any filtering, so you can widen the pattern set and rerun without
paying for collection twice.
Sample output
From a completed run against testphp.vulnweb.com, an application published as a
deliberately vulnerable test target.
The archive returns far more than is worth testing, which is why the filter runs
before the fuzzer. gf kept 66 URLs out of the archived set:
Those collapse into 55 fuzz targets once qsreplace swaps each
value for the marker:
Worth noticing in that list: several archived URLs carry SQL and script payloads
in their query strings, because the archive recorded somebody else's scan traffic
against this host years ago. The filter treats them as parameters like any other.
dalfox reported nothing on this run. It names the parameter, the
payload and the evidence of execution when it does fire, and a parameter that
reflects but does not execute is not reported, which keeps the PDF short enough to
act on.
FAQ
Does this find stored cross-site scripting?
No. It tests parameters for reflected and DOM cross-site scripting, which is what an
archive-and-fuzz approach can reach. Stored requires a value that is saved and then
rendered on a later page load, and nothing here does that.
Why archived URLs rather than a crawl?
A crawler sees what is linked today. The archive holds the page that shipped three years
ago, is still wired to the same template, and is still reachable from a link in an old
email. That is usually where the reflecting parameter is.
How is this different from running dalfox myself?
dalfox needs a candidate list, and building one is the first six steps.
This collects the archive, collapses URLs that differ only by parameter value, keeps the
ones matching known XSS patterns, then fans the fuzzing across the fleet instead of
walking the list one URL at a time.
Is it safe to run against a third party?
Collection reads public archives and sends nothing to the target. Fuzzing does send
payloads to the live application, so run the second half only inside a scope that allows
active testing, such as a bounty program that lists the domain.
What does a run cost?
The size of the archive sets the ceiling, but not the bill. Deduplication and pattern
filtering cut the list before the expensive step and the cap bounds it, so runtime tracks
the number of candidate parameters rather than the number of URLs the archive returned.
Related workflows
Find Open Redirects on a Domain. Reach for this instead when
the parameter you found controls a destination rather than page content.
Find SSRF in HTTP Parameters. Reach for this instead when the parameter is a
URL the server fetches and the payload never reaches a browser at all.
Find Secrets in Wayback Responses. Reach for this instead when
the same archived URL corpus is worth grepping for leaked keys before you spend a run
fuzzing it.