libFuzzer made easy. Open a C/C++ file, click a function, and fuzz it in minutes — no harness writing, no compiler flags to memorise.
Guzzle wraps libFuzzer in a desktop GUI that handles harness generation (via AI), compilation, live fuzzing, crash triage, and exploit scaffolding. It works on source files or pre-built libraries.
- Click any function in a C/C++ file to fuzz it
- AI-generated harness (DeepSeek, Claude, OpenAI, Ollama, or any OpenAI-compatible API)
- Harness caching — re-open a function instantly without a new AI call
- Compile with ASan + UBSan in one click
- Live fuzzer output, coverage stats, and crash detection
- Crash hex dump + reproduce command
- Gen PoC — compiles a standalone reproducer, extracts ROP gadgets, and uses AI to generate a pwntools exploit scaffold
- Library mode — link against pre-built
.a/.so/.dylibto fuzz third-party libraries
Kali Linux / Debian / Ubuntu
Tauri uses WebKitGTK as its rendering engine on all Linux desktops — including KDE. The GTK libraries are required regardless of your DE and coexist fine alongside Qt.
sudo apt update
sudo apt install -y \
build-essential \
curl \
wget \
file \
libssl-dev \
libgtk-3-dev \
libwebkit2gtk-4.1-dev \
libayatana-appindicator3-dev \
librsvg2-dev \
libglib2.0-dev \
libatk1.0-dev \
libgdk-pixbuf-2.0-dev \
libcairo2-dev \
libpango1.0-dev \
libasound2-devOn older Debian/Ubuntu,
libwebkit2gtk-4.1-devmay belibwebkit2gtk-4.0-dev.
sudo apt install -y clang llvm lldVerify libFuzzer is available:
echo '#include <stdint.h>
#include <stddef.h>
int LLVMFuzzerTestOneInput(const uint8_t *d, size_t s){return 0;}' \
| clang++ -x c++ - -fsanitize=fuzzer -o /tmp/guzzle_test && echo "OK"If that fails, the libFuzzer runtime may be in a separate package:
sudo apt install -y libclang-rt-devIf libclang-rt-dev doesn't exist (older distros ship versioned packages), find and install the matching version:
apt-cache search libclang-rt | grep "^libclang-rt-[0-9]"
# e.g. for clang-16:
sudo apt install -y libclang-rt-16-devcurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejsgit clone https://github.com/jabberwock/guzzle
cd guzzle
npm install
npm run tauri buildThe built app will be at src-tauri/target/release/guzzle.
To run in dev mode:
npm run tauri devmacOS
macOS ships with Apple Clang which does not include libFuzzer. You need LLVM from Homebrew:
brew install llvmGuzzle automatically finds Homebrew LLVM — no PATH changes needed. To verify manually:
echo '#include <stdint.h>
int LLVMFuzzerTestOneInput(const uint8_t *d, size_t s){return 0;}' \
| $(brew --prefix llvm)/bin/clang++ -x c++ - -fsanitize=fuzzer -o /tmp/guzzle_test && echo "OK"curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"brew install nodexcode-select --installgit clone https://github.com/jabberwock/guzzle
cd guzzle
npm install
npm run tauri buildThe built .app will be at src-tauri/target/release/bundle/macos/Guzzle.app.
To run in dev mode:
npm run tauri devWindows
Note: libFuzzer requires LLVM Clang — MSVC does not include it.
Download and install the latest LLVM release from releases.llvm.org.
During installation, select "Add LLVM to system PATH".
Verify:
clang --versionTo verify libFuzzer support, save this to test.cpp and compile it:
#include <stdint.h>
#include <stddef.h>
int LLVMFuzzerTestOneInput(const uint8_t *d, size_t s) { return 0; }clang++ -fsanitize=fuzzer test.cpp -o test.exeIf that fails, libFuzzer runtime is not bundled in your LLVM build — check the LLVM release notes for Windows fuzzer support.
Download and run rustup-init.exe.
Download from nodejs.org (v18+).
Required by Tauri — usually already present on Windows 10/11. If not: download here.
git clone https://github.com/jabberwock/guzzle
cd guzzle
npm install
npm run tauri buildUsage
- Click Open C/C++ File and select your
.c,.cpp, or.hfile - Click any line inside a function — a banner appears with the detected signature
- Click Fuzz this function → to open the wizard
- Toolchain — Guzzle checks your clang install automatically
- Harness — AI generates a fuzzing harness; review and edit it if needed. Previously accepted harnesses load instantly from cache.
- Compile — select sanitizers (ASan on by default) and compile
- Fuzzing — watch live output; crashes appear as they're found
- Results — view crash hex dumps, the reproduce command, and optionally generate a PoC script
- Pre-compile the library with fuzzer instrumentation:
CC=clang CFLAGS="-fsanitize=fuzzer-no-link,address" ./configure make - Open the library's header file (
.h) in Guzzle and click a function - In the Compile step, click + Add library and select your
.a/.dylib/.so - Add the header directory to Include Paths
- Compile and fuzz as normal
After a crash is found, select it in the Results panel and click Gen PoC. This:
- Compiles a standalone reproducer binary (no libFuzzer, no sanitizers,
-fno-stack-protector) - Verifies the crash reproduces
- Extracts ROP gadgets (see tool requirements below)
- Calls AI to generate a pwntools Python3 exploit scaffold
ROP tool requirements:
| Platform | Tool | Install |
|---|---|---|
| macOS | radare2 | brew install radare2 |
| Windows | radare2 | scoop install radare2 (via UniGetUI or Scoop) |
| Linux | ROPgadget or ropper | pip3 install ROPgadget |
To run the generated script:
pip3 install pwntools # if needed
# Linux only — disable ASLR:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
# macOS — disable ASLR in lldb:
# lldb -- ./reproducer <crash_file>
# (lldb) settings set target.disable-aslr true
python3 exploit.pyGen PoC only makes sense on heap/stack overflow crashes, not leaks. The crash types and what you can do with them:
| Prefix | Type | Exploitable? |
|---|---|---|
| crash- | SIGSEGV / heap-buffer-overflow | Yes — try Gen PoC |
| stack- | Stack overflow | Sometimes |
| leak- | Memory leak | No — nothing to exploit |
| oom- | Out of memory | No |
| timeout- | Hung | No |
Exits with code 0? The crash was caught by ASan but didn't produce a native SIGSEGV — common with small heap overflows. Confirm the bug is real with:
clang++ -O0 -g -fsanitize=address harness.cpp target.c reproducer_main.c -o asan_repro ./asan_repro .guzzle/crashes/crash-<hash>The pwntools script is most useful for stack-buffer-overflow crashes. Heap/UAF/double-free won't yield a traditional ROP chain, and offsets/libc addresses usually need manual tuning.
AI Providers
Guzzle supports multiple AI backends for harness generation and PoC scripting:
| Provider | Notes |
|---|---|
| DeepSeek (default) | Cheap, fast, good at C/C++ |
| Ollama | Fully local, no API key needed |
| Claude | Anthropic API — strong at understanding complex codebases |
| OpenAI | GPT-4o and friends |
| Custom | Any OpenAI-compatible endpoint |
API keys are stored in your OS keychain (Keychain on macOS, Secret Service on Linux, Credential Manager on Windows).
How it works
- Parsing — tree-sitter extracts the function signature at your cursor
- Harness generation — the AI receives the signature + surrounding code context and writes a
LLVMFuzzerTestOneInputharness; accepted harnesses are cached in.guzzle/harness_cache.jsonkeyed by file hash + function name - Compilation — Guzzle injects a preamble (
exit()intercept) and postamble, then compiles harness + target withclang++ -fsanitize=fuzzer,address - Fuzzing — the compiled binary is run as a libFuzzer target; output is streamed live
- Crash detection — crash files are watched in
.guzzle/crashes/and shown in the Results panel - PoC generation — a sanitizer-free reproducer is compiled, ROP gadgets extracted, and AI generates a pwntools exploit scaffold
Corpus and crashes are saved in .guzzle/ next to your source file:
.guzzle/
fuzzer # compiled fuzzer binary
reproducer # standalone crash reproducer (no ASan)
corpus/ # fuzzer-generated test cases
crashes/ # crash inputs
harness.cpp # the harness as compiled
harness_cache.json # cached AI-generated harnesses
Contributing
PRs and issues welcome. A few ground rules:
Before opening a PR
- Open an issue first for anything non-trivial so we can agree on direction
- Keep PRs focused — one thing per PR
- Test on at least one real C/C++ file end-to-end before submitting
Stack
- Frontend: Tauri 2 + React 18 + TypeScript + Tailwind CSS v4
- Backend: Rust (Tauri commands in
src-tauri/src/commands/) - Dev mode:
npm run tauri devfrom the project root
What's welcome
- Bug fixes (always welcome — please include steps to reproduce in the issue)
- New AI provider presets
- Better tree-sitter parsing for edge-case C/C++ signatures
- Distro-specific install fixes / docs
- Windows testing and fixes
What to avoid
- Large refactors without prior discussion
- Adding dependencies without a clear reason
- UI changes that break the existing wizard flow
libFuzzer note
When writing tests or verify commands, always use LLVMFuzzerTestOneInput as the entry point — never int main(). libFuzzer provides its own main() and the linker will reject a file that defines both.
- ryan_ (for the AGENT idea, making this a GUI or all-in-one CLI experience)
