---
title: 'Sydr-Fuzz: Hybrid Fuzzing & Dynamic Analysis'
url: https://www.emergentmind.com/topics/sydr-fuzz
type: topic
---

# Sydr-Fuzz: Hybrid Fuzzing & Dynamic Analysis

Searching arXiv for Sydr-Fuzz and closely related papers to ground the article in the cited literature.
Sydr-Fuzz is a continuous hybrid fuzzing and dynamic analysis framework designed to meet Security Development Lifecycle (SDL) requirements by automating fuzz testing, dynamic symbolic execution (DSE), security predicate checking, crash triaging, coverage reporting, and corpus minimization. It integrates the Sydr DSE engine with libFuzzer and AFL++ and orchestrates their collaboration in a CI/CD-friendly pipeline [2211.11595]. In the original formulation, the framework was motivated by a division of labor between coverage-guided fuzzers, which are fast at expanding coverage over simple constraints, and DSE, which is precise at solving complex path constraints but slower. Sydr-Fuzz combines these capabilities in a continuous testing workflow that also includes Casr for crash triage and a continuous fuzzing project, OSS-Sydr-Fuzz, which found 85 new real-world software flaws within one year [2211.11595].

## 1. Origin, scope, and design objectives

Sydr-Fuzz was introduced as “Continuous Hybrid Fuzzing and Dynamic Analysis for Security Development Lifecycle” and positions hybrid fuzzing as an SDL-oriented service rather than as a standalone experimental fuzzer [2211.11595]. Its stated components are a hybrid fuzzing orchestrator, the Sydr DSE tool, libFuzzer and AFL++, symbolic security predicate checkers, the Casr crash triaging tool, and utilities for corpus minimization and coverage gathering [2211.11595]. The framework’s key contributions include the first integration of a DSE tool, Sydr, with libFuzzer; a production-ready orchestrator that unifies hybrid fuzzing, symbolic security predicate checkers, corpus minimization, coverage gathering, and crash triaging; and practical optimizations in Sydr for hybrid fuzzing, including slicing, optimistic and strong optimistic solving, branch inversion cache, symbolic pointer handling and SMT-fuzzing of addresses, asynchronous solving, suspend-on-queue-threshold, standard-library semantics, constrained timeouts and memory limits, and flat output for seed exchange [2211.11595].

The underlying symbolic engine predates Sydr-Fuzz. Sydr itself was presented as a DSE system combining DynamoRIO dynamic binary instrumentation with the Triton symbolic engine, with path predicate slicing, branch inversion, jump-table handling, and multi-threaded symbolic state management [2011.09269]. This suggests that Sydr-Fuzz should be understood not merely as a wrapper around a symbolic executor, but as an orchestration layer that operationalizes Sydr’s branch inversion capabilities in a continuous fuzzing environment.

A later extension applied the same general architecture to directed greybox fuzzing by coupling Sydr with LibAFL-DiFuzz, adding a seed scheduling algorithm based on target-related interestingness and coverage, and objective minimization and sorting according to target-related information [2507.04855]. A plausible implication is that “Sydr-Fuzz” names both a concrete SDL pipeline and a broader family of hybrid workflows centered on Sydr plus an orchestrator.

## 2. Architecture and execution pipeline

The orchestrator is the central control component. It launches and coordinates Sydr and fuzzers, manages corpus directories, prioritizes seeds for DSE, and minimizes and exchanges test cases among workers [2211.11595]. Two binaries are required: an instrumented build for fuzzers, using sanitizers and coverage instrumentation, and a plain non-instrumented build for Sydr, which performs binary-level DSE [2211.11595]. In the baseline workflow, fuzzers mutate inputs, Sydr explores paths and generates targeted inputs by solving path constraints, and seeds flow bidirectionally: fuzzers can consume Sydr-generated inputs, while Sydr schedules promising fuzzer-discovered seeds for symbolic exploration [2211.11595].

The integration differs by fuzzer backend. In libFuzzer mode, all workers share a corpus directory; Sydr writes generated seeds directly into that directory; a patched libFuzzer counts reloads of Sydr-generated files; and Sydr cleans un-reloaded files to avoid noise [2211.11595]. Scheduling is driven by recorded coverage and features in libFuzzer logs, and the orchestrator parses a single active libFuzzer log to prioritize seeds and decide exit-on-time when coverage stagnates [2211.11595]. In AFL++ mode, Sydr runs as a “fake secondary worker,” writing minimized seeds with unique coverage to a Sydr worker queue directory, while crashes are saved separately; AFL++ imports interesting files from the Sydr queue, and the orchestrator tracks imports via AFL++ statistics and filenames [2211.11595].

The end-to-end pipeline comprises input generation, instrumentation, feedback collection, DSE guidance, corpus exchange, security predicate checking, crash triaging, coverage gathering, and corpus minimization [2211.11595]. Fuzzer builds use LLVM sanitizers and coverage instrumentation, whereas Sydr uses DynamoRIO for concrete execution and Triton-based symbolic execution [2211.11595]. After corpus minimization, Sydr checks symbolic security predicates to generate inputs that exercise potential vulnerabilities including null dereference, division by zero, integer overflow, and out-of-bounds memory access [2211.11595]. Crash handling is delegated to Casr: `casr-san` runs instrumented binaries on crashing seeds and generates structured reports, `casr-cluster` deduplicates and clusters based on stack traces, and `casr-gdb` produces detailed reports for non-instrumented binaries; reports are classified by exploitability [2211.11595].

For continuous operation, the pipeline exposes CLI tasks suitable for CI runners: `sydr-fuzz run`, `cmin`, `security`, `casr`, and `cov-report` [2211.11595]. The GitLab-based OSS-Sydr-Fuzz workflow uses a Docker builder, supports extending the initial corpus with previously found seeds, and emits minimized corpus artifacts, coverage, Casr reports, and seeds [2211.11595].

## 3. Dynamic symbolic execution in Sydr-Fuzz

Sydr-Fuzz inherits its symbolic execution model from Sydr. Concrete execution uses DynamoRIO, symbolic execution uses Triton extended to support the Bitwuzla SMT solver, and Sydr maintains parallel processes for concrete and symbolic execution plus a separate thread pool for solving constraints asynchronously [2211.11595]. In the earlier Sydr description, Conex performs dynamic binary instrumentation, intercepts input-handling system calls and libraries, and streams instruction-level execution events to Symex through shared memory; Symex tracks symbolic variables for inputs, symbolic register, memory, and file states, and path predicates [2011.09269]. Sydr performs concolic execution along the concrete path defined by the current input, symbolically executing only instructions whose operands are currently symbolic [2011.09269].

Path reasoning is formalized by the conjunction of observed branch constraints,
$$
\Phi(x) = \bigwedge_{k=1}^{n} c_k(x),
$$
where $c_k$ are branch constraints observed along the concrete path under input $x$ [2211.11595]. To reach new targets, Sydr uses sliced branch negation:
$$
\Phi'(x) = \Phi_{\text{slice}}(x) \land \neg b(x),
$$
where $\Phi_{\text{slice}}(x)$ retains only constraints data-dependent on the target branch and other constraints are concretized from the original seed [2211.11595]. The underlying Sydr paper presents the same idea as path predicate slicing followed by branch inversion and reports that slicing significantly increased the number of correct, branch-flipping inputs on several programs [2011.09269].

Several optimizations are specific to hybrid fuzzing. If $\Phi_{\text{slice}}(x)$ is UNSAT, Sydr constructs an optimistic predicate with only the target branch constraint $b(x)$, and then attempts a strong optimistic predicate by removing constraints using call-stack and control-dependency analysis [2211.11595]. Each symbolic branch is hashed in a branch inversion cache, and a per-branch counter guides repeated attempts when the counter is in powers of two until 255, while execution context is tracked to retry on changed paths [2211.11595]. Sydr can process symbolic pointers in a full mode that is accurate but heavy, or use SMT-fuzzing as a lightweight mode by enumerating solver models up to defined limits; the orchestrator periodically enables full symbolic pointer processing, for example every 25th Sydr launch [2211.11595]. It also supports inversion of switch statements, symbolic summaries for functions such as `strto*l`, `*alloc`, and `strcmp`, and bounded resource controls including single-query, total-solving, and per-run timeouts and memory caps [2211.11595].

The earlier Sydr evaluation provides context for these design choices. Skipping non-symbolic instructions made path predicate construction 1.2–3.5 times faster, and parallel solving increased the number of correct inversions in longer runs [2011.09269]. This suggests that the optimizations carried into Sydr-Fuzz are not ad hoc engineering additions, but DSE cost controls aimed at maximizing coverage under bounded solver budgets.

## 4. Guidance, scheduling, and corpus management

Coverage guidance in Sydr-Fuzz is based on coverage instrumentation and sanitizers in fuzzer builds, which produce coverage feedback and crash reports [2211.11595]. Coverage is summarized by
$$
C(S) = \text{number of unique edges covered by input set } S,
$$
and coverage progress is monitored to trigger pipeline stages and to stop fuzzing after stagnation [2211.11595]. Corpus minimization is defined as the optimization problem
$$
\text{find } S' \subseteq S \text{ to minimize } |S'| \text{ subject to } C(S') = C(S),
$$
with implementation differing by backend: AFL++ mode uses `afl-showmap` to gather bitmaps per seed, merge them into a global bitmap, and prune subsumed seeds, while libFuzzer mode relies on the shared corpus directory and libFuzzer’s corpus updates, with Sydr removing seeds not reloaded by libFuzzer [2211.11595].

Seed scheduling determines which corpus inputs are sent to Sydr. In libFuzzer mode, seeds are ordered by whether a new function was covered, whether new coverage was achieved, whether libFuzzer features increased, and descending `t_creation/S_seed`, so newer and smaller inputs are prioritized [2211.11595]. In AFL++ mode, ordering is based on new coverage, initial corpus labels, smaller file size, and newer file by id-ordered filename [2211.11595]. Resource allocation is typically one fuzzer instance and one Sydr instance per single-core trial, while Sydr uses asynchronous solver threads and suspends predicate building when queued branch inversions exceed a threshold [2211.11595].

A later directed-fuzzing version of Sydr-Fuzz introduces a distinct but related scheduling formulation. There, the orchestrator selects seeds from the LibAFL-DiFuzz corpus using a priority queue organized as a binary heap and lexicographically prioritizing `is_interesting_ets`, `is_interesting_map`, and `file_score`, where `file_score` is computed as file creation time divided by file size [2507.04855]. In that variant, synchronization from symbolic execution to the fuzzer occurs through a sync directory with a dynamic interval
$$
\Delta = \max(60, 3t),
$$
where $t$ is the time spent importing all seeds from the symbolic executor [2507.04855]. Although this formulation belongs to directed fuzzing rather than the original SDL paper, it illustrates how Sydr-Fuzz’s orchestration layer generalizes to other scheduling objectives.

The common principle across both versions is the use of seed metadata to govern DSE effort. This suggests that Sydr-Fuzz’s notion of “hybridization” includes not only seed exchange between fuzzers and symbolic execution, but also explicit prioritization policies that trade solver cost against expected utility.

## 5. Security predicates and crash triage

Beyond coverage expansion, Sydr-Fuzz performs targeted vulnerability-oriented input generation through symbolic security predicates [2211.11595]. During symbolic execution on a non-crashing seed, at each instruction operating on symbolic data, Sydr constructs a security predicate $SP(x)$ and solves
$$
SP(x) \land \Phi_{\text{slice}}(x)
$$
to generate an error-triggering seed [2211.11595]. The supported bug classes are null pointer dereference, division by zero, integer overflow, and out-of-bounds memory access, and some predicates map to multiple CWEs [2211.11595].

The predicate definitions are explicit. For null pointer dereference at memory-access instructions,
$$
SP(x) \equiv (addr(x) = 0).
$$
For division by zero at `div` or `idiv`,
$$
SP(x) \equiv (divisor(x) = 0).
$$
For out-of-bounds memory access at memory-access instructions,
$$
SP(x) \equiv (addr(x) < lower\_bound) \lor (addr(x) > upper\_bound),
$$
with bounds tracked using a shadow heap for `alloc`/`free` and a shadow stack for function-frame boundaries, with stack bounds approximated heuristically [2211.11595]. For integer overflow at arithmetic instructions,
$$
SP(x) \equiv (OF = 1)
$$
for signed results or
$$
SP(x) \equiv (CF = 1)
$$
for unsigned results, with signedness inferred from subsequent conditionals such as `JL`; the framework reports only cases in which a sink, such as a branch, dereference, or function argument, consumes the overflowed result [2211.11595].

Verification is performed automatically. The sanitizer build is run with the predicate-derived seed; if an error matches the reported source location, the result is accepted, otherwise the system re-runs the base corpus seed and checks for new sanitizer warnings [2211.11595]. Verified security predicate results are deduplicated by source file, line, and column [2211.11595]. Because predicate solving is heavier than branch inversion, Sydr provides a dedicated mode to separate security predicate checking from path exploration to preserve throughput [2211.11595].

Crash triage is handled by Casr. In formal terms, a crash signature is
$$
\sigma = H(\text{stack frames}, \text{signal}, \text{binary}, \text{code offset}),
$$
where $H$ is a hash over normalized stack frames and crash metadata; deduplication keeps only unique $\sigma$ [2211.11595]. Casr reports include OS and package versions, command line, stack trace, registers, a disassembly snippet with crash line, open files, sockets, and a severity classification—exploitable, probably exploitable, or not exploitable—inferred from trace, signal, and code context [2211.11595]. The pipeline emits clustered reports and associated triggering seeds, enabling direct reproduction from artifacts [2211.11595].

A common misconception is to view hybrid fuzzing solely as a coverage mechanism. In Sydr-Fuzz, coverage growth, predicate-based bug generation, and structured crash triage are part of one integrated SDL workflow [2211.11595].

## 6. Evaluation, impact, and relation to other systems

The main benchmarking campaign used FuzzBench on a server with 256 GB RAM and two AMD EPYC 7702 CPUs, with 10 trials per fuzzer-target combination, a single CPU core per trial, and 23 hours per trial [2211.11595]. Sydr-Fuzz was compared against libFuzzer, AFL++, SymQEMU, and FUZZOLIC on 15 coverage-oriented targets, with fewer targets for SymQEMU and FUZZOLIC due to target constraints [2211.11595]. The experimental Sydr configuration included one fuzzer and one Sydr instance per trial, direct branch inversion order, one solving thread, a 10-second per-query timeout, 60 seconds total solving time, a 2-minute per-run limit, inversion cache, strong optimistic solutions, symbolic address fuzzing with per-address model caps, periodic full symbolic pointer handling, suspension of predicate building after 300 queued inversions, and an 8 GB memory limit [2211.11595].

The reported results show higher coverage on 9 of 14 applications versus libFuzzer, with higher average normalized coverage in both target packs, approximately 98.7–99.6% versus 96.5–98.3% [2211.11595]. Against AFL++, Sydr-Fuzz likewise achieved higher coverage on 9 of 14 applications and higher average normalized coverage, approximately 98.8–99.2% versus 94.9–96.7% [2211.11595]. Against SymQEMU, it outperformed on 7 of 13 applications and achieved higher average normalized coverage in both packs, approximately 99.35–99.95% versus 97.03–99.67%, although SymQEMU showed instability on `sqlite3` [2211.11595]. Against FUZZOLIC, Sydr-Fuzz outperformed on 6 of 12 applications, showed strong advantages on `libjpeg-turbo` and `openthread`, and had similar average normalized coverage, approximately 99.1–99.84% versus 99.07–99.81%, while FUZZOLIC failed on `woff2` [2211.11595]. Sydr’s contribution measured by AFL++ imports was higher than SymQEMU and FUZZOLIC on 6 of 13 applications, though notably low on `zlib_uncompress` [2211.11595].

Real-world impact was demonstrated through OSS-Sydr-Fuzz, which found 85 previously unknown defects across 22 open-source projects over one year, including 13 found by security predicates [2211.11595]. The framework’s repositories make available build scripts, Dockerfiles, fuzz targets, configuration files, initial corpora, dictionaries, and CI pipeline integration materials, while Casr is open-source as a separate crash triage tool [2211.11595].

Relative to prior and contemporaneous systems, Sydr-Fuzz adopts seed exchange and caching ideas similar to QSYM but adds slicing, strong optimistic solving, asynchronous solving, and a CI-oriented orchestrator [2211.11595]. Compared with SymCC and SymQEMU, it targets binary-level execution via Triton and DynamoRIO and is characterized as the first-of-its-kind integration with libFuzzer [2211.11595]. Compared with FUZZOLIC, it provides a more general SDL pipeline and security predicates [2211.11595]. Compared with PASTIS, which brokers fuzzing and DSE to validate SAST alerts, Sydr-Fuzz generalizes hybrid fuzzing with corpus minimization, predicate-based bug finding, Casr triage, and continuous CI integration [2211.11595].

Known limitations remain. Tool operability varied across targets; single-core constraints and fixed timeouts affect the balance between solver and fuzzer; `sqlite3` was a weak case because poor DSE performance impaired overall hybrid effectiveness; and full symbolic pointer handling is costly and therefore enabled periodically [2211.11595]. Proposed future work includes AARCH64 support, Python fuzzing integration with Atheris, adjustment of `AFL_SYNC_TIME`, parsing debug information to refine array bounds for pointer reasoning and security predicates, a seed scheduler based on Katz graph centrality, and new security predicate checkers for integer truncation, format string, and command injection [2211.11595].

A later directed-fuzzing study showed that the Sydr-Fuzz approach also improves Time to Exposure in target-oriented settings, outperforming all tools on 3 of 7 examples with speedup up to 1.86 times over the second-best result and improving over pure LibAFL-DiFuzz on 3 of 7 examples with speedup up to 4.9 times [2507.04855]. This suggests that Sydr-Fuzz’s central idea—a continuously orchestrated exchange between a fuzzer and a concolic executor—extends beyond coverage maximization to target-driven testing regimes as well.

Source: https://www.emergentmind.com/topics/sydr-fuzz