Quality assurance testing for the curl project
99
stars
416
commits
C++
primary language
Sep 10, 2026
updated
Code and corpora for curl and libcurl fuzzing.
This is the curl fuzzing OSS-Fuzz runs for us, non-stop.
Great! Run ./mainline.sh. It will download you a fresh copy of curl, compile
it with clang, install it to a temporary directory, then compile the fuzzer
against curl. It'll also run the regression testcases.
If you have a local copy of curl that you want to use instead, pass the path as
an argument to ./mainline.sh. It will compile and install that curl to a
temporary directory instead.
./mainline.sh is run regressibly by Github Actions.
Run ./codecoverage.sh. It builds every fuzzer with LLVM source-based coverage
instrumentation, replays the checked-in corpora through them, and produces:
build-coverage/coverage/summary.txt - llvm-cov report (per-file line/region/function
percentages, restricted to curl's lib/ and src/).build-coverage/coverage/html/index.html - browsable HTML report.Like mainline.sh, pass -c /path/to/curl to measure coverage against a local
curl checkout instead of the git master tip.
The Coverage GitHub Actions workflow runs the same script on demand
(Actions → Coverage → "Run workflow") and uploads the report as an
artifact; the summary is also posted into the job summary page so the
overall number is visible without downloading anything. It's manual
rather than per-push to keep the main CI path fast.
Setting the FUZZ_VERBOSE environment variable turns on curl verbose logging.
This can be useful when debugging a single testcase.
Run ./scripts/download_public_corpus.sh. It pulls the public public.zip
for every target listed in scripts/fuzz_targets into
ossfuzz_corpus/<target>/, skipping any that don't have a published zip.
Pass -f to force a refresh of already-downloaded corpora.
./codecoverage.sh automatically replays ossfuzz_corpus/<target>/
alongside the checked-in corpora/<target>/ when the directory exists, so
local coverage numbers reflect what the OSS-Fuzz fleet has discovered. The
Coverage CI workflow runs the same download weekly (cached by ISO week).
The public corpus links for each target are also accessible directly:
curl_)curl_fuzzer_bufq; until OSS-Fuzz
picks up the new name, the live corpus remains at
curl_fuzzer_bufq
and the new location curl_fuzz_bufq will start filling in once the
rebuild propagates.Check out REPRODUCING.md for more detailed instructions.
python3 -m venv .venv
pip install .
uv; either
uv sync
uv pip install -e .
to sync your environment, or
uv run <tool>
directly.To look at the contents of a testcase, run
read_corpus <path/to/file>
This will print out a list of contents inside the file.
Generate a standalone HTML page that can inspect TLV corpora directly in your browser:
python -m curl_fuzzer_tools.generate_decoder_html
By default the generator writes to docs/corpus-decoder/index.html. The page is entirely client-side; it never uploads the selected file. You can open the output straight from the filesystem, for example file:///.../docs/corpus-decoder/index.html.
View the latest published decoder:
curl corpus decoder (GitHub Pages)
GitHub Pages is configured to deploy automatically from the docs/ folder whenever the main branch is updated. Use the command above locally before pushing if you need to refresh the published site.
The Playwright regression test is opt-in so the default install stays light. If you want to run it:
pip install -e '.[browser-tests]'
playwright install chromium
pytest tests/browser/test_corpus_decoder.py
These commands exercise the generated HTML by uploading a sample TLV corpus in a headless Chromium run.
To generate a new testcase, run
generate_corpus
with appropriate options - pass --help for all options.
Wonderful! Here's a bit of information you may need to know.
Testcases are written in a Type-Length-Value or TLV format. Each TLV has:
TLV type numbers are defined in both corpus.py and curl_fuzzer.h.
To add a new TLV:
generate_corpus.py, corpus.py.
This means adding options for reading the value of the TLV from the user (or
from a file, or from test data)curl_fuzzer.cc, curl_fuzzer.h. This
likely means adding handling of the TLV to fuzz_parse_tlv().FUZZ_CURLOPT_TRACKER_SPACE can encompass your additional TLVs!C++
44.0%
Python
23.6%
CMake
10.6%
Shell
8.3%
HTML
6.9%
C
6.7%
Quality assurance testing for the curl project
99
stars
416
commits
C++
primary language
Sep 10, 2026
updated
Code and corpora for curl and libcurl fuzzing.
This is the curl fuzzing OSS-Fuzz runs for us, non-stop.
Great! Run ./mainline.sh. It will download you a fresh copy of curl, compile
it with clang, install it to a temporary directory, then compile the fuzzer
against curl. It'll also run the regression testcases.
If you have a local copy of curl that you want to use instead, pass the path as
an argument to ./mainline.sh. It will compile and install that curl to a
temporary directory instead.
./mainline.sh is run regressibly by Github Actions.
Run ./codecoverage.sh. It builds every fuzzer with LLVM source-based coverage
instrumentation, replays the checked-in corpora through them, and produces:
build-coverage/coverage/summary.txt - llvm-cov report (per-file line/region/function
percentages, restricted to curl's lib/ and src/).build-coverage/coverage/html/index.html - browsable HTML report.Like mainline.sh, pass -c /path/to/curl to measure coverage against a local
curl checkout instead of the git master tip.
The Coverage GitHub Actions workflow runs the same script on demand
(Actions → Coverage → "Run workflow") and uploads the report as an
artifact; the summary is also posted into the job summary page so the
overall number is visible without downloading anything. It's manual
rather than per-push to keep the main CI path fast.
Setting the FUZZ_VERBOSE environment variable turns on curl verbose logging.
This can be useful when debugging a single testcase.
Run ./scripts/download_public_corpus.sh. It pulls the public public.zip
for every target listed in scripts/fuzz_targets into
ossfuzz_corpus/<target>/, skipping any that don't have a published zip.
Pass -f to force a refresh of already-downloaded corpora.
./codecoverage.sh automatically replays ossfuzz_corpus/<target>/
alongside the checked-in corpora/<target>/ when the directory exists, so
local coverage numbers reflect what the OSS-Fuzz fleet has discovered. The
Coverage CI workflow runs the same download weekly (cached by ISO week).
The public corpus links for each target are also accessible directly:
curl_)curl_fuzzer_bufq; until OSS-Fuzz
picks up the new name, the live corpus remains at
curl_fuzzer_bufq
and the new location curl_fuzz_bufq will start filling in once the
rebuild propagates.Check out REPRODUCING.md for more detailed instructions.
python3 -m venv .venv
pip install .
uv; either
uv sync
uv pip install -e .
to sync your environment, or
uv run <tool>
directly.To look at the contents of a testcase, run
read_corpus <path/to/file>
This will print out a list of contents inside the file.
Generate a standalone HTML page that can inspect TLV corpora directly in your browser:
python -m curl_fuzzer_tools.generate_decoder_html
By default the generator writes to docs/corpus-decoder/index.html. The page is entirely client-side; it never uploads the selected file. You can open the output straight from the filesystem, for example file:///.../docs/corpus-decoder/index.html.
View the latest published decoder:
curl corpus decoder (GitHub Pages)
GitHub Pages is configured to deploy automatically from the docs/ folder whenever the main branch is updated. Use the command above locally before pushing if you need to refresh the published site.
The Playwright regression test is opt-in so the default install stays light. If you want to run it:
pip install -e '.[browser-tests]'
playwright install chromium
pytest tests/browser/test_corpus_decoder.py
These commands exercise the generated HTML by uploading a sample TLV corpus in a headless Chromium run.
To generate a new testcase, run
generate_corpus
with appropriate options - pass --help for all options.
Wonderful! Here's a bit of information you may need to know.
Testcases are written in a Type-Length-Value or TLV format. Each TLV has:
TLV type numbers are defined in both corpus.py and curl_fuzzer.h.
To add a new TLV:
generate_corpus.py, corpus.py.
This means adding options for reading the value of the TLV from the user (or
from a file, or from test data)curl_fuzzer.cc, curl_fuzzer.h. This
likely means adding handling of the TLV to fuzz_parse_tlv().FUZZ_CURLOPT_TRACKER_SPACE can encompass your additional TLVs!C++
44.0%
Python
23.6%
CMake
10.6%
Shell
8.3%
HTML
6.9%
C
6.7%