Fuzzable: ranking fuzzing targets with static analysis
Framework for Automating Fuzzable Target Discovery with Static Analysis.
At a glance
- What is it?
- Fuzzable is a Python framework that scores functions in a binary or a source tree for how likely they are to be worth fuzzing, using weighted multi-criteria heuristics over symbol names, risky sinks, loops, complexity and call depth, then emits harness templates. It suits a researcher who knows what to fuzz but not where, and it does not fuzz anything itself.
- Who is it for?
- Adopt Fuzzable if you are assessing a large binary or an unfamiliar C or C++ codebase and you know how to write a harness but not which function to point it at, because that is the gap it fills. Do not adopt it expecting coverage, crash detection or a campaign, since it produces candidates and templates rather than findings.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 134 days ago.
- 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 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The gap Fuzzable targets: which function, not how to fuzz
Vulnerability researchers conducting security assessments on software harness the capabilities of coverage-guided fuzzing through tools like AFL++ and libFuzzer. Fuzzing automates the bug hunting process and reveals exploitable conditions in targets quickly, and the README is clear about that value.
The problem comes afterwards, or rather before. When the codebase is large and complex, or the target is a closed-source binary, the researcher has to spend a great deal of time manually auditing and reverse engineering the code to identify the functions where fuzzing-based exploration could be useful. That triage step is slow, and it is the step Fuzzable attacks.
Fuzzable is a framework that integrates with both C and C++ source code and binaries to help identify function targets that are viable for fuzzing. It does that by applying static analysis based heuristics to pinpoint risky behaviours in the software and the functions that execute them. From there, the researcher can use the framework to generate basic harness templates, which can then be used to hunt for vulnerabilities, or plugged into a continuous fuzzing pipeline such as Google's oss-fuzz project.
That last point is what makes the tool more than a lab experiment. A ranked list of targets and a set of starter harnesses is exactly the input a continuous fuzzing system needs, and the tool was featured at Black Hat Arsenal USA 2022, which is where the README points for the technical background.
The repository is MIT licensed, the default branch is `main`, and the last push to the tree was on 2026-06-11. The releases are older than that: v2.0.7 from 2023-11-22, v2.0.6 from 2023-03-25 and v2.0.5 from 2023-01-27.
Three backends: Binary Ninja, angr and tree-sitter
Fuzzable analyses two kinds of artifact with three different tools, and the choice of backend is a real decision rather than an implementation detail.
For binaries, the primary backend is Binary Ninja, and the README gives a specific reason. Some binary targets need sanitizing first, meaning signature matching or identifying functions that were inlined, and Binary Ninja is used primarily because of its ability to solve those problems effectively. An angr fallback backend is also supported, and the author frames the reason for it plainly: Binary Ninja is not accessible to all, and there may be a demand to use the tool for security assessments and potentially to scale up in the cloud. Other disassemblers are planned, with Ghidra named as the priority.
For source code, the backend is tree-sitter, which parses the source without needing a compiler database, so it works on a directory of files and headers rather than on a single build artefact.
The Binary Ninja integration is not just a backend choice, it is a second way to run the tool. Fuzzable runs as a standalone CLI, and it is also integrated as a plugin for the Binary Ninja disassembler, installable through the Binary Ninja plugin marketplace by going to `Binary Ninja > Manage Plugins` and searching for it. The plugin form puts the analysis inside the reverse engineering workflow, which is where a lot of the triage work already happens, and the README includes a screenshot of the plugin identifying targets for further vulnerability assessment.
The dependency list in the packaging metadata makes the stack concrete: typer for the CLI, angr, lief for binary parsing, tree-sitter for source parsing, and scikit-criteria for the scoring.
The five heuristics and their shipped weights
Fuzzability is decided by a set of weighted criteria, and the table in the README gives both the metrics and the default weights.
Fuzz Friendly Name carries a weight of 0.3 and scores a symbol whose name implies behaviour that ingests file or buffer input. Risky Sinks also carries 0.3, covering arguments that flow into risky calls such as memcpy. Coverage Depth is the third at 0.3, counting the number of callees the target traverses into. Natural Loops has a weight of 0.05, counting loops detected with the dominance frontier, and Cyclomatic Complexity has a weight of 0.05, based on edges plus nodes.
The weighting mechanism is scikit-criteria, which uses multi-criteria decision analysis to determine the best candidates. That is a different approach from a hand written scoring function, and it means the criteria are combined as alternatives rather than filtered one by one, so a function that scores badly on one metric can still rank highly through the others.
The metric choice is not arbitrary. The README credits many of the metrics as largely inspired by Vincenzo Iozzo's original work in 0-knowledge fuzzing, where the idea is to fuzz without prior knowledge of the target's internals. Coverage Depth at 0.3 is the highest weight among the three heavy criteria and the one that reflects that idea directly: a function that calls into a lot of other code has more surface for a fuzzer to reach.
The README also states the limitation of any such ranking directly, that every target is diverse and Fuzzable will not be able to account for every edge case behaviour in the program target. Which is precisely why the weights are tunable.
Tuning the weights, and the filtering that comes before scoring
Because the weights encode a judgement, the tool lets you replace them. The CLI takes a `--score-weights` argument with five comma separated values, one per heuristic, and the README gives an example that spreads the weight evenly.
$ fuzzable analyze <TARGET> --score-weights=0.2,0.2,0.2,0.2,0.2bash
This is the feature that decides whether the tool is useful for you. If you are fuzzing a network service, the functions that parse request buffers matter more than the ones with deep call graphs, and you would weight Fuzz Friendly Name and Risky Sinks accordingly. If you are looking for memory corruption in a file parser, Coverage Depth and Natural Loops may be the ones worth weighting up. The default weights are a reasonable starting point but they are one researcher's defaults, and the README's own advice is to tune them so that different results make sense for your use case.
The README then moves on to analysis filtering, and here the text available is cut off partway through the sentence describing the default behaviour, which filters out function targets. The section exists and the mechanism is a filter applied before or alongside the scoring, but the specific criteria are not visible in the text at hand, so the details have to come from the project documentation or the code rather than from this description.
The technical blog post linked from the README, at codemuch.tech, is the place the heuristics are explained in depth, and the README points there for that reason.
Installing it, and running it against a binary or a source tree
If you have Binary Ninja Commercial, the API has to be installed for standalone headless usage, which the README shows as a script inside the application bundle.
$ python3 /Applications/Binary\ Ninja.app/Contents/Resources/scripts/install_api.pybash
The package itself installs with pip.
$ pip install fuzzablebash
For a manual build, the project uses poetry for dependency management, and the clone is recursive because the third-party modules are submodules.
$ git clone --recursive https://github.com/ex0dus-0x/fuzzablebash
$ cd fuzzable/
# without poetry
$ pip install .
# with poetry
$ poetry install
# with poetry for a development virtualenv
$ poetry shellbash
The same `analyze` subcommand covers all three input kinds, and the difference is the path you give it: a single shared object library binary, a single C source file, or a directory holding multiple C and C++ files and headers.
# analyzing a single shared object library binary
$ fuzzable analyze examples/binaries/libbasic.so
# analyzing a single C source file
$ fuzzable analyze examples/source/libbasic.c
# analyzing a workspace with multiple C/C++ files and headers
$ fuzzable analyze examples/source/source_bundle/bash
The repository ships those same examples under `examples/binaries/` and `examples/source/`, alongside `templates/` for the harness output, `fuzzable/` for the package, `third_party/` for the vendored modules, `docs/` and `tests/`. There is also a `Dockerfile` that builds on ubuntu:20.04, installs Python 3 and pip, adds the project and installs it, and whose command is a shell, which is the container route to running the CLI without touching the host.
Where the ranking approach breaks down
There are three limitations worth being explicit about, and none of them are hidden by the project.
The first is the commercial dependency for the best backend. Binary Ninja is not free, and the README explains that the tool uses it primarily because some binary targets need sanitizing, meaning signature matching or identifying inlined functions. The angr fallback exists precisely because Binary Ninja is not accessible to all, but the fallback is a fallback, and if your target is a stripped or obfuscated binary, the quality of the analysis will reflect which backend you could afford. That is a procurement decision as much as a technical one.
The second is that a static ranking is a hypothesis, not a finding. Coverage Depth counts callees, which is a proxy for reachable code rather than a measurement of what a fuzzer would actually explore. A function with a deep call graph whose branches are all guarded by a magic value will rank well and fuzz badly. The README acknowledges that the tool cannot account for every edge case, and the only real check is a coverage-guided run afterwards, which is the step Fuzzable is designed to make cheap rather than to remove.
The third is that the output is a starting point, not a finished campaign. The generated harnesses are described as basic harness templates, which means they will need adjusting before they are useful, and getting a harness right for a particular function is a craft that the tool cannot do for you.
The alternative approach is worth naming precisely. Instead of ranking functions statically, you can run coverage-guided fuzzing over the whole binary and let the feedback decide, which is what AFL++ and libFuzzer are for, and you can use a fuzzing engine that supports structure-aware inputs, such as libFuzzer with a custom mutator, when the input format is known. The difference in approach is direct: Fuzzable decides where to look before you start, a coverage-guided fuzzer decides what to keep after you start. Fuzzing the whole binary works when the binary is small or the harness is trivial, and it becomes impractical when the attack surface is wide, which is the situation the ranking is designed for.
Editorial conclusion
Adopt Fuzzable if you are assessing a large binary or an unfamiliar C or C++ codebase and you know how to write a harness but not which function to point it at, because that is the gap it fills. Do not adopt it expecting coverage, crash detection or a campaign, since it produces candidates and templates rather than findings. Before you rely on the ranking, read the technical blog post it links, which explains why each metric exists, and re-run the analysis with `--score-weights` set to your own priorities, because the shipped weights encode one researcher's judgement about what makes a function fuzzable.
Frequently asked questions
What does Fuzzable actually do, and what does it not do?
It applies static analysis heuristics to functions in a binary or a C/C++ source tree, ranks them for fuzzing suitability, and generates basic harness templates. It does not fuzz anything itself, and it does not run a coverage-guided campaign.
Which disassemblers and parsers does Fuzzable support?
Binaries are analysed with Binary Ninja as the primary backend and angr as a fallback, and source code is analysed with tree-sitter. Ghidra is named as the priority for future backends, and Fuzzable also runs as a Binary Ninja plugin.
How do I change the scoring weights in Fuzzable?
Pass `--score-weights` with five comma separated values, one per heuristic, for example `fuzzable analyze <TARGET> --score-weights=0.2,0.2,0.2,0.2,0.2`. The README advises tuning the weights so that results make sense for your use case.
How do I install Fuzzable?
With `pip install fuzzable`, or from a manual clone of the repository with its submodules followed by `pip install .` or `poetry install`. If you have Binary Ninja Commercial, you also need to run the install_api.py script for standalone headless usage.
Official sources
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.
[](https://hysenlabs.com/projects/ex0dus-0x-fuzzable)Was this useful?