Skip to main content

Research framework for LLM-assisted vulnerability discovery: fuzzing, multi-agent triage, and binary analysis on one shared model

Project description

raon

raon is a research framework for LLM-assisted vulnerability discovery in C/C++. It compiles targets, fuzzes them under sanitizers, and normalizes, deduplicates, and ranks the resulting crashes into structured findings using a small set of cooperating agents. Language models are used to synthesize fuzzing harnesses and reason about findings, but never run inside the per-execution loop. raon orchestrates established tools — clang/AddressSanitizer, libFuzzer — rather than reimplementing them. Source-less (binary) analysis via angr is included but experimental.

CI License: MIT Python

English | 한국어 | 中文

Status

raon is in early development (pre-alpha); its API may change without notice, so pin a version (pip install "raon==0.1.0") if you depend on it. It is intended for security research, capture-the-flag exercises, and authorized testing only. Please read POLICY.md before use.

A self-contained evaluation shows raon detecting and correctly classifying several memory-bug classes end to end (see Benchmarking). Known-CVE reproduction via the Magma benchmark (which needs an x86_64 Linux host) has not been run yet; no CVE-reproduction rates are claimed until it is.

Features

  • Compiles C/C++ targets with clang under AddressSanitizer/UndefinedBehaviorSanitizer and runs inputs against them.
  • Coverage-guided fuzzing through libFuzzer harnesses (on platforms where the libFuzzer runtime is available).
  • Parses ASan, UBSan, LeakSanitizer, and ThreadSanitizer reports into normalized findings.
  • Deduplicates crashes with a normalized-stack key that is stable across rebuilds, and ranks findings by exploitability.
  • Synthesizes fuzzing harnesses from function signatures, with a self-repairing compile loop.
  • Stores targets, corpora, and findings in a single, concurrency-safe SQLite store.
  • Optional Claude integration with model tiering, response caching, and full request logging.

Requirements

  • Python 3.10 or newer
  • clang with AddressSanitizer, to compile and fuzz targets
  • Docker (optional), for a reproducible Linux environment that includes the libFuzzer runtime
  • An Anthropic API key (optional), only for harness synthesis and LLM-based reasoning

Installation

pip install raon                 # core
pip install 'raon[llm]'          # with the Claude provider
pip install 'raon[binary]'       # with angr/LIEF for source-less targets (experimental)
pip install 'raon[dev]'          # with development tools

Because the API may change during pre-alpha, pin the version for reproducible installs: pip install "raon==0.1.0".

Usage

Command line

# Compile a target, run inputs, triage crashes, then store and rank the findings
raon run mytarget.c --input seed.bin --input crash.bin --db raon.sqlite

# Parse a saved sanitizer crash report into a finding (no compiler required)
raon triage crash_report.txt --target-id my_target --db raon.sqlite

# Rank stored findings by exploitability, with duplicates collapsed
raon report --db raon.sqlite

Python

from raon.store import Blackboard
from raon.agents import AgentB, Supervisor

with Blackboard("raon.sqlite") as store:
    finding = AgentB().triage(open("crash.txt").read(),
                              target_id="my_target", reproducer="poc.bin")
    store.put_finding(finding)

    result = Supervisor().triage(store.list_findings())
    for f in result.representatives:
        print(f.category, f.exploitability, f.dedup_key[:12])

Harness synthesis and inference use Claude. Compose a provider once; responses are cached and every request is logged:

from raon.llm import build_provider, PromptCache, JsonlLogger
from raon.llm.anthropic_provider import AnthropicProvider

provider = build_provider(
    AnthropicProvider(),                    # reads ANTHROPIC_API_KEY
    cache=PromptCache(".raon/cache"),
    logger=JsonlLogger(".raon/llm.jsonl"),
)

Everything except harness synthesis and LLM-based reasoning works without an API key.

Overview

raon runs the fuzzer as a native subprocess and calls a language model only at decision points — writing a harness, summarizing a crash, proposing a fuzzing target. Components communicate through a small set of shared record types on one store, so they remain independent and every artifact a run produces can be inspected.

Package Description
raon.fuzzing Compiles targets with clang and sanitizers, runs them, parses crash reports, synthesizes harnesses
raon.agents Interprets crashes, static-analysis results, and weak-interface hypotheses into findings
raon.triage Deduplicates crashes, weighs evidence, ranks by exploitability
raon.store Shared SQLite store for targets, corpora, and findings
raon.llm Claude integration with model tiering, response caching, and logging
raon.knowledge Domain packs (for example, PNG) providing seeds and weak-interface hints
raon.bench Reads Magma benchmark ground truth and computes metrics
raon.binary Maps crash addresses to functions and recovers types for source-less targets (experimental)
raon.contracts The shared record types every component reads and writes

A crash is represented as a Finding: a category, its evidence, a confidence, an exploitability score, and a dedup_key. The dedup_key is a normalized stack hash that omits addresses, line numbers, and build paths, so the same bug maps to the same key across rebuilds.

Agents

"Multi-agent" here means three focused agents plus a supervisor, coordinating through the shared store rather than by calling each other directly. Each agent produces Findings; the supervisor merges them. The static and inference agents are optional and require their respective tools.

Agent Role Evidence produced
AgentA Static analysis (runs Semgrep, interprets results) static path, medium confidence
AgentB Crash triage — parses sanitizer output from a run dynamic crash, high confidence
AgentC Interface inference from domain knowledge (weak-interface hypotheses) inference, low confidence
Supervisor Orchestration — deduplicates, weighs evidence across agents, ranks by exploitability merged, ranked findings

Evidence is weighted by kind (a reproducible dynamic crash outranks a static path, which outranks an inference), so a confirmed crash dominates a speculative one for the same bug. The quickstart above shows only AgentB + Supervisor for brevity; AgentA/AgentC follow the same interface. (These names are slated to become role-based in a future release — see CHANGELOG.md.)

Platform support

Platform ASan fuzzing (raon run) Coverage-guided fuzzing (libFuzzer) Triage / Python API / CLI
Linux (x86_64)
macOS (Apple clang) ❌ (no libFuzzer runtime)
Windows ⚠️ untested (use WSL) ⚠️ untested (use WSL)
Docker (provided image)

raon run and integration tests need clang with AddressSanitizer. Coverage-guided fuzzing additionally needs the libFuzzer runtime, which ships with Linux clang but not Apple clang; the provided docker/Dockerfile gives a Linux environment with both. Triage, the Python API, and the CLI work anywhere Python 3.10+ runs.

Benchmarking

Self-contained evaluation. raon ships a small benchmark of libFuzzer targets with planted bugs (plus a safe target as a false-positive check) and runs the full pipeline against them. Measured results (raon 0.2.0, Docker image):

Target Bug class Detected Sanitizer error Time to crash (s)
heap_overflow.c memory heap-buffer-overflow 0.04
use_after_free.c memory heap-use-after-free 0.03
stack_overflow.c memory stack-buffer-overflow 0.03
global_overflow.c memory global-buffer-overflow 0.03
safe.c — (safe) no crash ✓

4/4 buggy targets detected, 0 false positives. Reproduce with docker run --rm raon:ci python -m raon.bench.eval. Details and methodology: docs/evaluation.md.

Orchestration value (single vs. multi-agent). On the same bugs run repeatedly (raw stacks vary with ASLR), a naive single-pass baseline over-reports 4 bugs as 12 (dedup F1 0.00); raon's normalized dedup + Supervisor recovers exactly 4 (F1 1.00). Reproduce with python -m raon.bench.experiment.

Magma (planned). raon also includes an adapter (raon.bench) that reads the Magma benchmark's canary ground truth for known-CVE reproduction metrics. Running those campaigns requires an x86_64 Linux host with Docker; results will be published once a campaign has run. No CVE-reproduction rates are claimed until then.

Documentation

Building and testing

pip install -e '.[dev,llm]'
ruff check src tests      # lint
mypy                      # static type checking
pytest -q                 # test suite (fuzzing tests run when clang is present)
pytest -q -m "not integration"   # unit tests only

To run the full suite in a reproducible Linux environment (with libFuzzer):

docker build -f docker/Dockerfile -t raon:ci .
docker run --rm raon:ci

Contributing

Contributions are welcome. Please read CONTRIBUTING.md for the development workflow, coding standards, and the checks that must pass before a pull request. All use of the project must follow POLICY.md.

License

Licensed under the MIT License. Copyright © 2026 Junwon Lee.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

raon-0.3.0.tar.gz (93.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

raon-0.3.0-py3-none-any.whl (82.0 kB view details)

Uploaded Python 3

File details

Details for the file raon-0.3.0.tar.gz.

File metadata

  • Download URL: raon-0.3.0.tar.gz
  • Upload date:
  • Size: 93.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for raon-0.3.0.tar.gz
Algorithm Hash digest
SHA256 f14fea39c3d80cc0f020909af06dc0c5cd4793c0c73b45a9f2b76904e254f1b8
MD5 c6be5b10924058882c078cabf245fb3a
BLAKE2b-256 1d955a4107e402f49556c6e7f091975e0e4ab82dd9e78900a61137d7f10cedc3

See more details on using hashes here.

File details

Details for the file raon-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: raon-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 82.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.2

File hashes

Hashes for raon-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 53a2e29d10eb0ffa7117666f99d60f4e8fdac6f659c49e7420b72b471b476119
MD5 b26a48226c10f0a64c324ff34fb3886f
BLAKE2b-256 98a9c898fcac51f24424e597d886c97843b3847ff7e5425846450e0857ce9386

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page