Open-source project
tlsfuzzer/tlsfuzzer avatar
tlsfuzzer/tlsfuzzer

tlsfuzzer checks that a TLS server returns the right errors, not just that it survives

SSL and TLS protocol test suite and fuzzer

637 stars137 forksPythonGPL-2.0

At a glance

What is it?
tlsfuzzer is a GPL licensed Python test suite and fuzzer for SSLv2, SSLv3, TLS 1.0 through 1.3 implementations, built on tlslite-ng, with ready made scripts for known attacks such as ROBOT and DROWN and for RFC conformance. Its distinguishing idea is that a script checks the error the server returned, so a wrong alert is a failure even when nothing crashes, and the project is explicit that it verifies TLS level behaviour only, not certificates.
Who is it for?
TLS implementers and auditors who need evidence that a server rejects malformed handshakes with the right alerts, rather than evidence that it does not crash, will find the script library and the expectation checking model genuinely useful, and the attack specific scripts cover cases a generic scanner will not.
Can I use it commercially?
Yes, with conditions. GPL-2.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 received new commits within the last day.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A fuzzer that asserts on the error message

tlsfuzzer is described as a test suite for SSLv2, SSLv3, TLS 1.0, TLS 1.1, TLS 1.2 and TLS 1.3 implementations, and the difference between it and a typical fuzzer is stated in the documentation in one paragraph. It uses fuzzing techniques, meaning randomisation of passed in inputs, but the scripts are generally written to verify correct error handling. Unlike typical fuzzers it does not check only that the system under test did not crash, it checks that it returned correct error messages. That is a much stronger oracle, and it is why the tool is used in audits rather than only for crash hunting. The project is also candid about its own maturity, saying it is in early stages of development with no API stability guarantees, and the package version in the setup script is 0.0.1. The scope of the protocol coverage is broad, from SSLv2 to TLS 1.3, and the scripts directory holds ready to use tests for many vulnerabilities, including ROBOT and DROWN, along with general standards conformity tests for RFC 5246, RFC 7627 and RFC 7905.

tlslite-ng, and the tlslite package it conflicts with

The dependency list is short and has one sharp edge. You need Python 2.6 or later, or Python 3.6 or later, and tlslite-ng 0.8.1 or later, and the note in the documentation is explicit that `tlslite` will not work and that the two conflict with each other. The setup script states the requirement as tlslite-ng 0.8.2 or later, alongside the python-ecdsa module at version 0.15 or later, which is a dependency of tlslite-ng and is expected to be installed with it, and the documentation notes that version 0.15 is the point at which performance is optimal. Two optional native libraries are recommended if you want the cryptographic calculations to be significantly faster, m2crypto and gmpy, and the documentation points at the tlslite-ng and python-ecdsa readme files for details on those. The install sequence is pip first, then the checkout:

bash
python get-pip.py
bash
pip install --pre tlslite-ng
bash
git clone https://github.com/tlsfuzzer/tlsfuzzer.git

The `--pre` flag is needed because the pinned tlslite-ng release in the requirements file, 0.9.0b2, is a beta.

Pointing a script at a server on port 4433

Running a test has four preconditions, and they are the sort of thing that causes confusion if you skip them. You must be in the project directory after the clone, the server you want to test must be running on the same computer, it must be listening on port 4433, and it will answer with data to HTTP queries, though answering with valid HTTP responses is optional. Then a script from the `scripts/` directory is run directly:

bash
scripts/test-invalid-compression-methods.py

If a test has extra requirements it prints them to the console, and the success convention is worth internalising: no errors printed means all expectations were met, so for tests that send bad data, the server rejected the messages. Every script accepts `--help` for the full option list, `-h` for the hostname or IP address of the server under test and `-p` for the port. The deeper documentation lives in USAGE.md, which covers how to interpret the errors and failures that scripts report, and the project documentation is published at tlsfuzzer.readthedocs.io.

Preparing the server under test

The documentation gives concrete commands for the three server stacks most likely to be under test, which is what makes this project usable without prior setup knowledge. In general the server needs just an RSA certificate, created with:

bash
openssl req -x509 -newkey rsa -keyout localhost.key -out localhost.crt -subj \
/CN=localhost -nodes -batch

For OpenSSL, passing an extra `-www` option to a typical `s_server` command line is enough:

bash
openssl s_server -key localhost.key -cert localhost.crt -www

For GnuTLS, the server has to be told to behave as an HTTP server and not to ask for client certificates:

bash
gnutls-serv --http -p 4433 --x509keyfile localhost.key --x509certfile \
localhost.crt --disable-client-cert

NSS needs a database built first, with `certutil`, `openssl pkcs12` and `pk12util`, and then the server is started with `selfserv` on port 4433 with TLS 1.0 and later enabled and the DHE ciphers. A wiki page covers the more advanced configurations and how to compile the servers from source.

No certificate checks, and that is deliberate

The scope limit is stated in bold in the documentation, and it is the first thing to check before drawing conclusions from a run. tlsfuzzer verifies only TLS level behaviour and does not perform any checks on the certificate, listing hostname validation, CA signatures and key usage as examples of what is not done. It does verify that signatures made on TLS messages by the server, such as the Server Key Exchange or Certificate Verify message, match the certificate the server sent. So the tool tells you whether the handshake is handled correctly, not whether the certificate is any good. For a reviewer this matters a great deal, because a clean tlsfuzzer run is not evidence of a valid chain of trust, and pairing it with a certificate checker is a separate task. The same principle applies to the side channel work, which is documented separately in TIMING.md, covering Lucky13, padding oracle attacks and timing based Bleichenbacher oracle testing.

CI enforces a 90 percent diff on coverage and lint

The Makefile shows how the project keeps its own quality bar high, which is a signal worth reading before you judge the script library. The default target prints the two commands that matter, installing with `./setup.py install` or `make install` and testing with `make test`. The test target builds the documentation first, then runs the unit test suite under coverage with branch coverage, once under Python 2 and once under Python 3, reporting and then generating XML and HTML coverage output. It then runs a script that verifies the JSON test definitions, and it runs pylint over the `tlsfuzzer` package, saving the report, and finally compares both the pylint report and the coverage XML against the `origin/master` branch with diff-quality and diff-cover, both with a fail-under of 90. In other words, a change that reduces coverage or introduces lint problems fails the build. There is also a separate `test-scripts` target that checks the script retention against the tlslite-ng scripts. The repository carries a `sbom.cdx.json` software bill of materials, a pylintrc, a `.vale.ini` for prose linting, and separate build requirement files for several Python versions.

An active project with no tagged releases

tlsfuzzer is a long running security tool by Hubert Kario, and the repository layout reflects a working audit toolkit rather than a packaged library. The root holds the `tlsfuzzer/` package with a `utils` subpackage, the `scripts/` directory that is the actual point of the project, `3rd-party-scripts/` for tests taken from elsewhere, `tests/`, `docs/`, a Makefile, a `setup.py` and `setup.cfg`, a `pyproject.toml` that selects the setuptools backend, and a set of documents for contributors, `CONTRIBUTING.md`, `VISION.md` for the planned scope of the project, `USAGE.md`, `TIMING.md` and `CODE_OF_CONDUCT.md`. The licence is GPL-2.0, which suits a security testing tool that organisations run against their own servers. There are no GitHub releases, so the version to track is the one in the setup script, 0.0.1, and the last push to the repository was on 2026-10-20 with the repository not archived. Contributors are expected to follow the code of conduct, and the README points contributors at the contributing document for the development environment and the requirements a change has to meet.

Editorial conclusion

TLS implementers and auditors who need evidence that a server rejects malformed handshakes with the right alerts, rather than evidence that it does not crash, will find the script library and the expectation checking model genuinely useful, and the attack specific scripts cover cases a generic scanner will not. It is the wrong tool for certificate and PKI assessment, because the documentation states it performs no hostname validation, CA signature or key usage checks, and the wrong tool for continuous integration against a production endpoint since it needs a server under test on localhost. Before running it, set up the target server with the documented OpenSSL, GnuTLS or NSS commands, and read TIMING.md if the question is about side channels rather than conformance.

Frequently asked questions

What does tlsfuzzer check that a normal fuzzer does not?

It checks the error messages, not just the absence of a crash. The documentation says that unlike typical fuzzers it does not check only that the system under test did not crash, it checks that it returned correct error messages, and a script that prints no errors means the server rejected the malformed messages as expected.

Does tlsfuzzer validate certificates?

No. The documentation states that it verifies only TLS level behaviour and performs no certificate checks such as hostname validation, CA signatures or key usage. It does verify that signatures on TLS messages match the certificate the server sent.

How do I run a tlsfuzzer script?

The server under test must be running on the same machine and listening on port 4433. Then run a script from the scripts directory, for example `scripts/test-invalid-compression-methods.py`, with `-h` for the hostname and `-p` for the port, and `--help` for the full option list.

Which vulnerabilities does tlsfuzzer have ready-made scripts for?

The documentation points to ready-to-use scripts for many vulnerabilities, naming ROBOT and DROWN, along with general standards conformity scripts for RFC 5246, RFC 7627 and RFC 7905. All of them live in the scripts directory of the repository.

Can tlsfuzzer test for timing side channel attacks?

Yes, and that is covered in a separate document, TIMING.md, which describes using tlsfuzzer to test for Lucky13, padding oracle attacks and timing based Bleichenbacher oracle. The setup script also ships analysis extras with matplotlib, numpy, pandas and scipy for that work.

Official sources

  1. Issues
  2. License: GPL-2.0
  3. README
  4. tlsfuzzer/tlsfuzzer on GitHub
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/tlsfuzzer-tlsfuzzer.svg)](https://hysenlabs.com/projects/tlsfuzzer-tlsfuzzer)

Was this useful?