SPRAY fuzzes directories with masks, rule files and fingerprints
最好用最智能最可控的目录Fuzz工具 | The most powerful, user-friendly, intelligent, and precise HTTP Fuzzer.
At a glance
- What is it?
- SPRAY is a Go HTTP directory fuzzer that can build its wordlist from a mask, from a hashcat style rule file or from plain lists, fingerprint what it finds, filter the results and resume a run after an interruption. It is aimed at authorised assessment work, and the README is unusually candid about what it has not built yet.
- Who is it for?
- SPRAY suits a red team or security engineer doing authorised web reconnaissance who wants dictionary generation, fingerprinting and result filtering in one tool, and who is comfortable reading the wiki for the details the README leaves out. It does not suit a team that needs a distributed scanner today, because the cloud function distribution item in the TODO list is unchecked, and it is the wrong tool for any assessment performed without written authorisation for the target.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 95 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 21, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Three ways to produce the wordlist
SPRAY is a directory fuzzer, and the interesting part is that the list of paths to try is not always a list. Three generation modes are documented.
The plain mode reads directories from wordlists, and several lists can be given at once:
spray -u http://example.com -d wordlist1.txt -d wordlist2.txtThe mask mode generates the paths from a template, where the braces carry the pattern to expand:
spray -u http://example.com -w "/aaa/bbb{?l#4}/ccc"The rule mode applies a rule file to a base wordlist, and the format follows hashcat's rule syntax for dictionary generation:
spray -u http://example.com -r rule.txt -d 1.txtThat third mode is the interesting one for a tester, because the hashcat rule format is a known standard and a tester who already maintains rules for password cracking can reuse the same thinking for paths. The mask mode fills the gap when the structure of the target is known in advance, and the plain mode is the fallback.
Multiple targets are handled by putting the URLs in a file, and the same rule and dictionary combination is applied to each of them:
spray -l url.txt -r rule.txt -d 1.txtSo the tool separates the target list from the payload generation, which is what makes a batch run over a list of hosts practical.
Fingerprinting turns a 200 into a finding
A fuzzer that only reports status codes gives you a lot of noise, so SPRAY spends a lot of its weight on identifying what a response actually is. The project claims full fingerprint recognition from gogo, the full FingerprintHub database and wappalyzer fingerprints.
Fingerprinting is on by default in the check-only mode, which is described as similar to the single page information gathering approach of tools like ehole and httpx, with targeted performance optimisations, and it uses the templates finger library from the chainreactors templates repository:
spray -l url.txt --check-onlyExtended fingerprinting is switched on separately with --finger, which actively probes common fingerprint directories and additionally enables the FingerprintHub and wappalyzer extension libraries:
spray -u http://example.com --fingerThere is also a crawler, which changes the tool from a path prober into something that follows the site:
spray -u http://example.com --crawlAnd a mode for the classic misconfiguration hunt, scanning for backup files and common files:
spray -u http://example.com --bak --commonEnabling all plugins at once is the -a flag. The repository root has a fingers/ directory and a templates entry alongside cmd/, core/ and pkg/, so the fingerprint data ships with the source rather than being downloaded at run time, and config.yaml holds the tool's configuration.
Filtering is the feature the author wanted
The author's own account of why the tool exists appears in the list of similar projects. The most used directory fuzzer before spray was feroxbuster, and the reason for writing a new one was that batch scanning and filter configuration were inconvenient. Another project, httpx, contributed the idea of writing arbitrary filter conditions through a script language.
That explains the dependency list. The project requires github.com/expr-lang/expr, an expression language, and that is the mechanism behind the described dynamic intelligent filtering and custom filter strategies. The difference in approach against a plain fuzzer is that the decision about what to keep is a programmable expression rather than a fixed list of status codes and sizes, which matters when the interesting signal is a page title, a specific header, a body substring or a combination.
There is also custom information extraction with built-in rules for sensitive information, and custom output formats and content. The project describes its command line design as following Unix conventions so that it composes with other tools, and the dependency on github.com/imroc/req/v3 and github.com/valyala/fasthttp confirms that HTTP handling is done through fast libraries rather than the standard library, with mpb/v8 for progress bars and lipgloss for terminal styling.
The author also borrows from other tools openly, which is worth noting for anyone assessing provenance: dirsearch provided the default dictionary and some of the colour scheme, fuzzuli provided an idea for generating backup file lists, and the FingerprintHub and wappalyzer projects are credited as fingerprint sources.
Resuming, batching and the problem of being blocked
A scan against a real host can be interrupted, and SPRAY handles that with a state file:
spray --resume stat.jsonThe feature list also claims multiple angles of automatic detection of being banned or judged by a WAF, which is a security tool's way of describing evasive behaviour built into the request logic. The repository dependency on refraction-networking/utls is consistent with that, since uTLS is a library for mimicking browser TLS fingerprints.
Proxy support exists, but the README flags it as not recommended and low priority, for a specific reason: the keep alive behaviour of a proxy causes severe performance degradation. That is an unusually concrete warning, and it is the kind of detail that tells you the performance claims were observed rather than assumed.
Those performance claims need to be read carefully, because they are the author's own. The README states that in local testing of extreme performance scenarios the tool can exceed ffuf and feroxbuster by more than fifty percent, that actual results depend on the network and are not as clear in practice, and that the difference is noticeable across multiple targets. It is a comparison the project makes about itself, on its own hardware, with network conditions as a stated confounder, not a benchmark result you can rely on for your own target.
Two checklist items are still open
The TODO list in the README is a reasonable place to judge how finished this is. The completed items are the fuzzing comparison, resuming after interruption, a simple crawler, HTTP 2 support, custom recursive configuration, and automatic backup scanning of discovered directories, which is credited to feroxbuster's --collect-backups idea.
Two items are unchecked. The first is auto-tune, which would adjust the concurrency automatically, so the concurrency level is currently something you set and manage. The second is cloud function based distribution, described as a general distributed solution for the chainreactors tool chain. Both are meaningful omissions for scale. Auto-tune in particular means that a large run is either too slow or too aggressive depending on the setting you pick, and there is no built in assistance in choosing it.
The proxy item is checked but explicitly discouraged, which is a different thing from being supported well. Proxy support is there for routing, and the keep alive penalty makes it unattractive for high volume work.
For a reader deciding whether to adopt the tool, the honest summary is that single host work is well covered, batch work across many hosts is the case the author optimised for, and distributed work is not built yet.
Building it and running the first scan
The project is built from source with the Go toolchain, and the clone needs the submodules, which is why the README uses the --recurse-submodules flag:
git clone --recurse-submodules https://github.com/chainreactors/spray
cd spray
go mod tidy
go generate
go build .The go.mod requires Go 1.25.4, and the module list shows how much of the tool is shared with the rest of the author's project, with chainreactors/files, fingers, logs, neutron, proton, proxyclient, utils, parsers and words as dependencies alongside the general purpose libraries. The generate step matters because the fingerprint data and any embedded resources are produced there, and the build then produces the spray binary in the working directory. There is a .goreleaser.yml in the repository, which is how the tagged releases are packaged.
The first thing to try is the smallest possible run against a host you are authorised to test, with a short dictionary and the check-only mode, so that you can see the fingerprinting output and the filter behaviour before you point a mask or a rule file at anything. Then add the --crawl, --bak and --common options one at a time, because each of them changes how many requests the tool makes.
If you need the full reference, the README points to the wiki at chainreactors.github.io/wiki/spray/ for detailed usage.
Editorial conclusion
SPRAY suits a red team or security engineer doing authorised web reconnaissance who wants dictionary generation, fingerprinting and result filtering in one tool, and who is comfortable reading the wiki for the details the README leaves out. It does not suit a team that needs a distributed scanner today, because the cloud function distribution item in the TODO list is unchecked, and it is the wrong tool for any assessment performed without written authorisation for the target. Verify first that the build you use matches the go.mod requirement of Go 1.25.4, and expect to consult the wiki at chainreactors.github.io for the full filter and configuration reference.
Frequently asked questions
What is SPRAY and what does it do?
SPRAY is a Go HTTP fuzzer for directory discovery that can take its paths from wordlists, from a mask template, or from a hashcat style rule file applied to a base list, and then fingerprints, filters and reports the results.
How do I build SPRAY from source?
Clone the repository with submodules, then run go mod tidy, go generate and go build . The module requires Go 1.25.4, and the generate step produces the embedded resources used by the build.
Can SPRAY resume an interrupted scan?
Yes. The state is written to a file and a stopped run can be continued with spray --resume stat.json, and the resume feature is listed as complete in the project TODO.
Does SPRAY support proxy connections?
Support for socks and http proxies is implemented but the README recommends against using it, noting that proxy keep alive causes severe performance degradation and that the feature is low priority.
What is the difference between check-only mode and the full fuzzing mode?
Check-only mode gathers information about single pages in a style similar to ehole or httpx, using the templates finger library by default with targeted performance optimisations. Full mode fuzzes paths, and adding --finger additionally enables active probing of common fingerprint directories plus the FingerprintHub and wappalyzer extension libraries.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/chainreactors-spray)Was this useful?