⚠️ DisclaimerThe development of GlazGo has progressed significantly beyond the version previously uploaded to this GitHub repository.
At this time, the latest source code will not be shared publicly. Only compiled
.exereleases will be made available for download through the official release section.This approach allows for cleaner releases while development continues in a more experimental and evolving form.
Thanks for checking it out and supporting this early-stage project.
A web application fuzzer with a browser UI, written in Go. Point it at a request, mark the parts you want to vary with a keyword, and give each keyword a source of payloads.
No external dependencies: the UI, the built-in wordlists and the server all ship in one binary.
Any part of the request, at as many points at once as you like:
| Position | Example |
|---|---|
url, path |
https://host/FUZZ, https://host/?q=FUZZ |
method |
FUZZ /admin |
header-name |
FUZZ: 127.0.0.1 — accepted-header discovery, 403 bypass |
header-value |
X-Forwarded-For: FUZZ |
cookie-name, cookie-value |
session=FUZZ |
body |
user=admin&pass=FUZZ |
Two ways to describe the request:
- Structured — the usual URL, method, headers, cookies and body fields.
- Raw — paste a request from Burp and put keywords anywhere in it. Header names keep the case you wrote. (Go sorts header names on the wire, so header order is not preserved.)
Both compile to the same raw request internally, so they behave identically. Preview request shows exactly what will be sent.
A payload in the Host header is delivered to the original target rather than being resolved as a
hostname, which is what Host-header testing needs. A keyword in the URL's authority
(https://FUZZ.example.com/) is treated as subdomain fuzzing and does move the connection.
Every source streams one payload at a time, so memory does not depend on how many payloads there are. A 10M-line wordlist runs in about 22MB of RSS.
| Source | Notes |
|---|---|
| Wordlist file | Streamed line by line. Optionally pre-counted so progress can show a total. |
| Pasted payloads | Typed straight into the page. |
| Built-in list | Embedded in the binary: 403/401 bypass headers, cache-poisoning headers, loopback and internal address representations. |
| Number range | from/to/step with optional zero padding. Generated, no file. |
| Brute force | Every string over a character set within a length range. Generated, no file. |
| Mutations | Variants of another source: extensions, prefixes, suffixes, case, backup suffixes (.bak, ~, .old, …), leet. One base word becomes K payloads at no memory cost. |
With more than one fuzz point, choose how they combine:
- Clusterbomb — every combination.
- Pitchfork — sources advance in lockstep, for paired data such as user/password columns.
Each point has its own encoding: none, URL (minimal), URL (strict), double URL, or form. The minimal
URL encoding leaves /, ., ?, & and existing %xx escapes alone, so directory wordlists work,
but escapes spaces, # and the characters that would otherwise corrupt the request line.
Go 1.21 or later. No other dependencies.
go build -o glazgo ./cmd/glazgo./glazgoThen open http://127.0.0.1:5000/.
Flags:
| Flag | Default | Meaning |
|---|---|---|
-host |
127.0.0.1 |
Address to bind. |
-port |
5000 |
Port to listen on. |
-data |
data |
Directory for result logs. |
-open |
off | Open the UI in the default browser. |
The server binds loopback by default, and rejects cross-origin POST /api/*. The API can send
requests from this machine and read local files, so think before using -host 0.0.0.0: there is no
authentication.
| Setting | Meaning |
|---|---|
| Concurrent requests | Size of the worker pool. Also sizes the connection pool. |
| Timeout | Per-request timeout in milliseconds. |
| Rate limit | Cap on requests per second across all workers. 0 is unlimited. |
| Per-worker delay | Sleep after each request, per worker. The effective rate is roughly concurrency ÷ delay, which is why the rate limit exists. |
| Auto-pause after N failures | Pauses the run after N consecutive failures so a dead target does not burn through a wordlist. -1 disables it. |
| Keep results per status | Retention buffer per status code. Counters are unaffected. Adjustable during a run. |
| Calibration probes | How many "cannot exist" requests are sent to learn the not-found response. |
| Proxy | e.g. http://127.0.0.1:8080 to route through Burp. |
| Skip TLS verification | For targets with self-signed certificates. |
| Follow redirects | Off by default: a redirect is usually the finding. |
| Allow HTTP/2 | Negotiate h2 over TLS. |
| Accept gzip | Off by default so response lengths stay comparable between requests. |
| Match / Filter rules | Narrow what is listed and logged. Counts always cover every request. |
A directory run against a real target sends thousands of requests and gets one answer thousands of times. Two things deal with that without any configuration:
Auto-calibration. Before the run, GlazGo asks the target for a few paths that cannot exist and learns what it says. Responses matching that fingerprint are hidden. In a verified run of 40,004 requests this reduced the list to the 4 real pages.
It declines rather than guess. If the probe responses disagree — a page carrying a timestamp, a CSRF token, or genuinely random content — it reports "calibration inconclusive" and filters nothing, because a wrong fingerprint silently buries real findings. It never hides failed requests, and everything it does hide is still counted and still grouped. Switch it off with the checkbox.
Grouping. Identical responses collapse into one row: ×40,000 · 404 · len 88 · words 6. The
count is kept server-side, so it stays true for results already dropped from the display buffer.
"Show these" drills into a group.
Sortable on every column — click a header: request number, status, length, Δ against the baseline, words, lines, response time, content type, page title, payload, and whether the payload was reflected in the response body. Only the visible rows exist in the page, so a 50,000-row run scrolls as smoothly as a 50-row one.
title and reflected are the two most useful triage columns: the title tells you what a
discovered page actually is, and reflection is how parameters and injection candidates surface.
Quick filters above the table apply instantly to what is already retained, in both directions:
| Field | Accepts |
|---|---|
| Status, Length, Words, Time | 200, 400-499, 4xx, >1024, <=512, and ! to exclude — !404 |
| Payload, Title | substring, ! to exclude |
A field holding only exclusions means "everything except those". The status tabs above
(All · 200 (4) · 404 (40,000)) narrow to one status in a click.
Two separate limits, which behave differently:
- Show per status is a display cap. It applies instantly and changes nothing on the server.
- Keep per status is server-side retention. Lowering it drops the oldest immediately; raising it applies only to results from that point on — anything already dropped is gone.
The Match and Filter columns on the Fuzzer tab decide what is kept and written to disk for the whole run, on status, length, words, lines, time, and regexes on title and body. A result must satisfy every Match rule and is dropped if it satisfies any Filter rule. Failed requests are always kept, so an unreachable target is never filtered into looking like a target with no findings.
Body regex sees the first 64KB of a response, since bodies are never stored.
CSV, JSON, JSONL, or a plain list of URLs, covering what is retained with the rules and calibration already applied. The URL list feeds straight into another tool.
Written to <data>/<host>/<status>.txt, plus errors.txt for failures. GET runs log the bare URL so
the files stay usable as input to other tools. Hidden results are not logged — that is the point of
hiding them — but they are always counted and grouped.
A failure writing the logs is reported while the run is going, and Ctrl+C stops the run and flushes the buffer before exiting.
cmd/glazgo entry point and flags
internal/server HTTP API, embedded UI (web/)
internal/engine worker pool, run state, pacing
internal/httpx request template, substitution, encoding, client
internal/payload payload sources, generators, combination modes
internal/store result buffer, counters, log writer
internal/cli console output
The UI lives in internal/server/web as ordinary HTML, CSS and JavaScript, embedded at build time.
Edit it there.
The Windows icon comes from cmd/glazgo/glazgo_windows_amd64.syso. To regenerate it from
glazgo.rc / glazgo.ico, run rsrc in cmd/glazgo and keep the _windows_amd64 suffix, or
non-Windows builds will fail to link it.
go test ./...The concurrency work matters here, so prefer the race detector (it needs cgo and a C compiler):
go test -race ./...MIT — see the LICENSE file.