fix: improve fuzz targets to exercise real IronClaw code paths

- fuzz_config_env: exercise SafetyLayer end-to-end (sanitize, validate,
  policy check) instead of generic TOML/JSON parsing
- fuzz_tool_params: add validate_tool_schema coverage alongside
  validate_tool_params
- Add "fuzz" to workspace exclude in root Cargo.toml
- Update README descriptions to match actual target behavior

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 <[email protected]>
This commit is contained in:
2026-03-09 23:09:25 -07:00
co-authored by Claude Opus 4.6
parent e41eb8ae33
commit 3c6f4a97dc
4 changed files with 29 additions and 6 deletions
+1
View File
@@ -14,6 +14,7 @@ exclude = [
"tools-src/google-slides",
"tools-src/slack",
"tools-src/telegram",
"fuzz",
]
[package]
+2 -2
View File
@@ -9,8 +9,8 @@ Fuzz testing for security-critical input parsing paths using [cargo-fuzz](https:
| `fuzz_safety_sanitizer` | Prompt injection pattern detection (Aho-Corasick + regex) |
| `fuzz_safety_validator` | Input validation (length, encoding, forbidden patterns) |
| `fuzz_leak_detector` | Secret leak detection (API keys, tokens, credentials) |
| `fuzz_tool_params` | Tool parameter JSON validation pipeline |
| `fuzz_config_env` | Configuration parsing (TOML, JSON) |
| `fuzz_tool_params` | Tool parameter and schema JSON validation |
| `fuzz_config_env` | SafetyLayer end-to-end (sanitize, validate, policy check) |
## Setup
+21 -4
View File
@@ -1,12 +1,29 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
use ironclaw::config::SafetyConfig;
fuzz_target!(|data: &[u8]| {
if let Ok(s) = std::str::from_utf8(data) {
// Exercise TOML config parsing with arbitrary input
let _ = toml::from_str::<toml::Value>(s);
// SafetyConfig fields are parsed from env vars. We cannot safely set
// env vars in a multi-threaded fuzzer, but we can exercise the types
// that config parsing produces by constructing SafetyConfig directly
// and feeding the fuzzed string through the safety layer it creates.
// Exercise JSON config parsing
let _ = serde_json::from_str::<serde_json::Value>(s);
// Parse the fuzzed input as a potential max_output_length value.
let max_len: usize = s.parse().unwrap_or(100_000);
let config = SafetyConfig {
max_output_length: max_len,
injection_check_enabled: true,
};
// Build a SafetyLayer from the config and exercise it.
let layer = ironclaw::safety::SafetyLayer::new(&config);
// Use the fuzzed string as tool output content.
let _ = layer.sanitize_tool_output("fuzz_tool", s);
let _ = layer.validate_input(s);
let _ = layer.check_policy(s);
}
});
+5
View File
@@ -1,17 +1,22 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
use ironclaw::safety::Validator;
use ironclaw::tools::validate_tool_schema;
fuzz_target!(|data: &[u8]| {
if let Ok(s) = std::str::from_utf8(data) {
// Try parsing as JSON and validating as tool parameters
if let Ok(value) = serde_json::from_str::<serde_json::Value>(s) {
// Exercise Validator::validate_tool_params with arbitrary JSON
let validator = Validator::new();
let result = validator.validate_tool_params(&value);
// Invariant: result should always be well-formed
if !result.is_valid {
assert!(!result.errors.is_empty());
}
// Exercise validate_tool_schema with arbitrary JSON as a schema
let _ = validate_tool_schema(&value, "fuzz");
}
}
});