Back to Articles

Building Payload Generators for ffuf: The Unix Pipeline Approach to Web Fuzzing

[ View on GitHub ]

Building Payload Generators for ffuf: The Unix Pipeline Approach to Web Fuzzing

Hook

The most elegant fuzzing payloads aren't stored in files—they're generated on-the-fly through Unix pipes, creating millions of attack combinations without ever touching disk.

Context

Web application security testing demands vast amounts of structured input data. Testing authentication endpoints alone requires trying combinations of usernames and passwords—a Cartesian product that explodes exponentially. If you have 1,000 usernames and 1,000 passwords, you're looking at one million combinations. Store those as a pre-generated wordlist, and you're managing a file with over 50MB of repetitive data. Scale that to multiple attack patterns (base64 encoding, different delimiters, case variations), and wordlist management becomes its own infrastructure problem.

The ffuf-scripts repository takes a different approach: treating payload generation as a streaming problem rather than a storage problem. Instead of maintaining massive pre-computed wordlists, these shell scripts generate payloads dynamically and pipe them directly into ffuf, the fast web fuzzer written in Go. This shifts the paradigm from "store everything you might need" to "compute what you need, when you need it." It's a return to Unix philosophy: small tools that do one thing well and compose cleanly through pipes.

Technical Insight

ffuf Fuzzing Engine

Payload Generation

Base64 encode

Cartesian product

Wordlist Files

Shell Script Generator

Transformation Logic

stdout Stream

ffuf stdin -w -:KEYWORD

HTTP Fuzzing Requests

Basic Auth Headers

User:Pass Combinations

System architecture — auto-generated

The architecture of ffuf-scripts is deceptively simple, but that simplicity reveals sophisticated understanding of how fuzzing tools should integrate. Each script acts as a specialized iterator that outputs to stdout, designed to be consumed by ffuf's stdin wordlist feature using the -w -:KEYWORD flag pattern. The hyphen tells ffuf to read from stdin, and the keyword defines where in the request template to inject each generated payload.

The basicauth script demonstrates this pattern perfectly. Rather than requiring pre-generated lists of Base64-encoded credentials, it reads two wordlists and generates authentication headers on demand:

#!/bin/bash
# Usage: ./basicauth-generator.sh users.txt passwords.txt | ffuf -w -:BASIC

userlist=$1
passlist=$2

while IFS= read -r user; do
    while IFS= read -r pass; do
        creds=$(echo -n "$user:$pass" | base64)
        echo "Basic $creds"
    done < "$passlist"
done < "$userlist"

This script embodies several key design decisions. First, it uses nested loops to create a Cartesian product—every username paired with every password. Second, it handles the encoding inline using echo -n (crucial to avoid newline contamination) and pipes to base64. Third, it formats the output as a complete Authorization header value, ready for injection. The -n flag in echo is particularly important: without it, the newline character gets encoded into the base64 string, producing invalid credentials that will never authenticate.

The integration with ffuf looks like this:

./basicauth-generator.sh users.txt passwords.txt | \
  ffuf -u https://api.example.com/admin \
       -H "Authorization: BASIC" \
       -w -:BASIC \
       -mc 200

Here, ffuf receives each generated header value and substitutes it for the BASIC keyword. The -mc 200 flag tells ffuf to match only HTTP 200 responses, filtering successful authentications from the noise. This pipeline approach means you never materialize the full combination space—each credential is generated, tested, and discarded in a streaming fashion.

The pattern extends naturally to other fuzzing scenarios. Imagine a script that generates JWT tokens with varying claims, or one that creates SQL injection payloads with different encoding schemes. The template is always the same: read input, transform, output to stdout. The scripts become payload adapters, translating static wordlists into dynamic, context-appropriate attack patterns.

This architecture also enables composition. You could chain multiple transformations:

cat endpoints.txt | \
  ./add-parameters.sh params.txt | \
  ./url-encode.sh | \
  ffuf -u https://example.com/FUZZ -w -:FUZZ

Each script in the chain performs one transformation, and the final output feeds into ffuf. This is Unix pipeline thinking applied to offensive security: small, composable tools that maximize flexibility while minimizing code duplication.

The performance characteristics are worth noting. Shell scripts aren't known for speed, but for fuzzing workflows, the bottleneck is rarely payload generation—it's network I/O. When ffuf is waiting for HTTP responses, the script has ample time to generate the next batch of payloads. The synchronous nature of the pipeline provides natural backpressure: if ffuf can't consume payloads fast enough, the script blocks on stdout writes. No complex buffering or queue management required.

Gotcha

The repository's current state is sparse—essentially one example script and a README. While the pattern it demonstrates is valuable, you're not getting a comprehensive toolkit. If you need payload generators for other scenarios (GraphQL fuzzing, API parameter manipulation, JWT crafting), you'll be writing those scripts yourself using the basicauth example as a template. This is more of a reference implementation than a batteries-included solution.

Performance can become a concern with truly massive wordlists. Shell scripts excel at simplicity but struggle with computational intensity. If you're generating tens of millions of payloads with complex transformations (multiple encoding passes, cryptographic operations), the script overhead becomes measurable. The basicauth script, for instance, spawns a new base64 process for every single credential pair. With 10,000 usernames and 10,000 passwords, that's 100 million process forks. On modern systems this might take minutes, while a compiled Go or Rust equivalent could finish in seconds. Additionally, there's no error handling. If a wordlist file doesn't exist or contains malformed data, the script fails silently or produces garbage output that wastes fuzzing time.

Verdict

Use if: You're already a ffuf user who needs to generate combinatorial payloads (especially authentication credentials) and values the simplicity of shell scripts over raw performance. This repository shines when you need to quickly prototype custom payload generators without reaching for a compiled language, or when you want to understand the stdin integration pattern for building your own ffuf extensions. It's ideal for scenarios where wordlist sizes are manageable (thousands of entries, not millions) and the pattern it demonstrates is directly applicable to your fuzzing workflow. Skip if: You need a comprehensive, ready-to-use collection of payload generators for diverse attack scenarios—you won't find that here. Also skip if you're working with enormous wordlists where shell script overhead becomes prohibitive, or if you require robust error handling and input validation. Consider alternatives like custom Python scripts (better performance, easier error handling) or pre-generated wordlists from SecLists for common scenarios where dynamic generation adds no value.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/developer-tools/ffuf-ffuf-scripts.svg)](https://starlog.is/api/badge-click/developer-tools/ffuf-ffuf-scripts)