Skip to content

External Tools Integration

Crucible's built-in triage handles replay and evidence contracts, while dedicated tools can add clustering and byte minimization. Their labels remain hypotheses until verified with process facts and target source.

CASR: Crash Analysis and Severity Rating

CASR provides automated crash clustering and heuristic severity labels for sanitizer-detected crashes. Check its current release requirements before installing.

Installation

# Install from crates.io (requires Rust toolchain)
cargo install casr --locked

# Verify
casr-libfuzzer --version

Triaging libFuzzer Crashes

Use casr-libfuzzer to process a crash directory against a harness binary:

casr-libfuzzer \
  -i ./crashes/deep \
  -o ./casr-out/deep \
  -- ./harness/libfuzzer/crucible-libfuzzer-deep

This replays each crash file, captures the sanitizer output, and writes a .casrep JSON report per crash.

Clustering

Use casr-cluster to deduplicate and group crashes by stack similarity:

# Deduplicate
casr-cluster -d ./casr-out/deep

# Cluster into groups
casr-cluster -c ./casr-out/deep ./casr-clusters/deep

The cluster output directory contains one subdirectory per similarity cluster, with a representative .casrep and related artifacts. A cluster is not necessarily one source-level bug.

Interpreting Results

CASR reports include:

  • Heuristic severity: Labels such as Exploitable or Probably Exploitable; do not use them as a ratified impact assessment
  • Crash class: ASAN-specific crash type (e.g., heap-buffer-overflow)
  • Stack trace: Full sanitizer stack trace
  • Registers: CPU register state at crash point (when available)

CASR vs. Crucible Triage

CASR and Crucible triage are complementary. crucible-triage focuses on replay with process facts, Exact/Stable identities, target attribution, taxonomy hints, and SARIF export. CASR excels at large-scale crash clustering. Feed representatives into Crucible as candidate inputs, then replay and inspect them; neither clusterer confirms a vulnerability or severity.

Batch Processing Multiple Campaigns

# Process all campaign directories
for campaign in deep model rpc-commands rpc-race whisper-audio; do
  casr-libfuzzer \
    -i "./crashes/${campaign}" \
    -o "./casr-out/${campaign}" \
    -- "./harness/libfuzzer/crucible-libfuzzer-${campaign}"
  casr-cluster -c "./casr-out/${campaign}" "./casr-clusters/${campaign}"
done

# Summary of unique crashes per campaign
for d in ./casr-clusters/*/; do
  echo "$(basename "$d"): $(ls -d "$d"/*/ 2>/dev/null | wc -l) unique"
done

halfempty: Crash Minimization

halfempty uses bisection strategies to minimize crash reproducers. Smaller reproducers make root cause analysis easier and produce cleaner CVE reports.

Installation

# Build from source (requires glib2 development headers)
# Fedora/RHEL:
sudo dnf install glib2-devel

# Ubuntu/Debian:
sudo apt install libglib2.0-dev

git clone https://github.com/googleprojectzero/halfempty.git
cd halfempty
make
sudo cp halfempty /usr/local/bin/

Minimizing a Crash

halfempty requires a script that exits 0 for "interesting" and non-zero otherwise. The predicate must preserve the expected identity, not merely the crash class; a smaller input can fall into a different bug.

Implement the predicate with triage.ObserveReplay plus triage.Identify, comparing ExactNamespace and Exact to the original witness. Until that wrapper exists, use Crucible's built-in identity-preserving minimization rather than a text grep.

Strategies

Strategy Description Best For
bisect Binary search removal of byte ranges General purpose, fastest
zero Replace byte ranges with zeros Preserving file structure
delete Remove individual bytes Fine-grained minimization

Integration with Crucible Triage

Minimize crashes before triaging for cleaner reports:

Built-in minimization

crucible-triage --minimize natively recurses into crash subdirectories and preserves directory structure, reducing the need for external minimization tools in many workflows. Use halfempty when you need fine-grained control over the minimization strategy (bisect vs. zero vs. delete).

# Built-in minimization preserves the observed identity.
crucible-triage --artifact-kind input --crashes ./casr-clusters/deep \
  --harness ./harness/libfuzzer/crucible-libfuzzer-deep \
  --minimize --output ./reports

Workflow: Full Pipeline

A complete triage pipeline combining all tools:

flowchart TD
    A[Fuzzing Campaign] --> B[Raw Crashes]
    B --> C[CASR: Similarity clusters]
    C --> D[Candidate representatives]
    D --> E[halfempty: Minimize]
    E --> F[Minimized Reproducers]
    F --> G[crucible-triage: Reports + SARIF]
    G --> H[Markdown Reports]
    G --> I[SARIF for CI]
# 1. Cluster with CASR
casr-libfuzzer -i ./crashes/deep -o ./casr-out -- ./harness/libfuzzer/crucible-libfuzzer-deep
casr-cluster -c ./casr-out ./casr-clusters

# 2. Replay candidates, minimize by identity, and generate internal reports and SARIF
crucible-triage \
  --artifact-kind input \
  --crashes ./casr-clusters \
  --harness ./harness/libfuzzer/crucible-libfuzzer-deep \
  --minimize \
  --output ./reports \
  --sarif ./results.sarif