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
libaflfuzzing 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.