Skip to main content

Crate canfuzz

Crate canfuzz 

Source
Expand description

A coverage-guided fuzzing framework for Internet Computer canisters.

This framework is built on libafl and pocket-ic to find bugs in IC canisters by automatically generating and executing a vast number of inputs. It supports both Rust and Motoko canisters.

§Getting Started

To create a fuzzer, implement the orchestrator::FuzzerOrchestrator trait. This trait defines the setup and execution logic for your fuzzing campaign.

use canfuzz::fuzzer::{CanisterBuilder, FuzzerBuilder, FuzzerState, WasmPath};
use canfuzz::orchestrator::FuzzerOrchestrator;
use canfuzz::libafl::executors::ExitKind;
use canfuzz::libafl::inputs::BytesInput;
use std::path::PathBuf;

// 1. Define a struct for your fuzzer using the macro.
canfuzz::define_fuzzer_state!(MyFuzzer);

// 2. Implement the fuzzing logic.
impl FuzzerOrchestrator for MyFuzzer {
    fn init(&mut self) {
        // Setup PocketIc and install canisters automatically.
        self.as_mut().setup_canisters();
    }

    fn corpus_dir(&self) -> PathBuf {
        PathBuf::from("./corpus")
    }

    fn execute(&self, input: BytesInput) -> ExitKind {
        let payload: Vec<u8> = input.into();
        println!("Executing input: {:?}", payload);
        // Execute a canister call with the input.
        ExitKind::Ok
    }
}

// 4. Set up and run the fuzzer.
fn main() {
    let canister = CanisterBuilder::new("my_target_canister")
        .with_wasm_path("./my_canister.wasm")
        .as_coverage()
        .build();

    let state = FuzzerBuilder::new()
        .name("my_fuzzer")
        .with_canister(canister)
        .build();

    let mut fuzzer = MyFuzzer(state);
    fuzzer.run();
}

§Instruction Count Maximization

To maximize the number of IC instructions consumed by a canister method, enable instruction counting during wasm instrumentation and override FuzzerOrchestrator::instruction_config to return an InstructionConfig with enabled: true. No changes to the target canister source code are required — the framework automatically wraps exported methods to read ic0.performance_counter. Each time a new maximum is reached, the input is logged and saved to the corpus directory. Optionally set max_instruction_count to flag inputs that exceed a threshold as crashes.

See the decode_candid_by_instructions example for a complete demonstration.

For a complete example, see the examples/ directory in the project repository.

Re-exports§

pub use libafl;
pub use libafl_bolts;

Modules§

custom
Custom libafl components for canister fuzzing.
fuzzer
instrumentation
This module provides functionality to instrument WebAssembly (Wasm) modules for coverage-guided fuzzing, specifically implementing an AFL-style instrumentation.
orchestrator
This module orchestrates the fuzzing process using the libafl fuzzing framework.
util

Macros§

define_fuzzer_state
run_fuzzing_loop
Macro to avoid duplicating the fuzzing loop for different observer/feedback/stage type tuples. The observer tuple, feedback composition, and mutation stages differ depending on configuration (instruction count, Candid mutator), but the rest of the loop (state, executor, corpus loading) is identical.