Files
optimclaw/fuzz/fuzz_targets/fuzz_config_env.rs
T
c148dd2b5b feat: add fuzzing targets for untrusted input parsers (#835)
* feat: add fuzzing targets for untrusted input parsers

Add cargo-fuzz infrastructure with 5 fuzz targets exercising
security-critical code paths:

- fuzz_safety_sanitizer: Aho-Corasick + regex injection detection
- fuzz_safety_validator: Input validation (length, encoding, patterns)
- fuzz_leak_detector: Secret leak scanning (API keys, tokens)
- fuzz_tool_params: Tool parameter JSON validation
- fuzz_config_env: TOML/JSON config parsing

Each target exercises real IronClaw business logic with invariant
assertions. Includes corpus directories and setup documentation.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* 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]>

* fix: replace redundant detect() call with meaningful invariant assertion

Replace the double sanitize()+detect() call with an assertion that
critical severity warnings always trigger content modification.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix: rewrite fuzz_config_env to exercise IronClaw safety code directly

Replace SafetyLayer wrapper usage with direct Sanitizer, Validator, and
LeakDetector instantiation and invocation. Adds meaningful consistency
assertions (non-empty output, valid-means-no-errors, scan/clean agreement).
Removes the config construction that was only exercising struct instantiation.

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 <[email protected]>

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
2026-03-10 11:06:50 -07:00

56 lines
2.1 KiB
Rust

#![no_main]
use libfuzzer_sys::fuzz_target;
use ironclaw::safety::{LeakDetector, Sanitizer, Validator};
fuzz_target!(|data: &[u8]| {
if let Ok(input) = std::str::from_utf8(data) {
// Exercise Sanitizer: detect and neutralize prompt injection attempts.
let sanitizer = Sanitizer::new();
let sanitized = sanitizer.sanitize(input);
// The sanitized content must never be empty when input is non-empty,
// because sanitization wraps/escapes rather than deleting.
if !input.is_empty() {
assert!(
!sanitized.content.is_empty(),
"sanitize() produced empty content for non-empty input"
);
}
// If no modification occurred, content must equal input.
if !sanitized.was_modified {
assert_eq!(sanitized.content, input);
}
// Exercise Validator: input validation (length, encoding, patterns).
let validator = Validator::new();
let result = validator.validate(input);
// ValidationResult must always be well-formed: if valid, no errors.
if result.is_valid {
assert!(
result.errors.is_empty(),
"valid result should have no errors"
);
}
// Exercise LeakDetector: secret detection (API keys, tokens, etc.).
let detector = LeakDetector::new();
let scan = detector.scan(input);
// scan_and_clean must not panic and must return valid UTF-8.
let cleaned = detector.scan_and_clean(input);
if let Ok(ref clean_str) = cleaned {
// Cleaned output must never be longer than original + redaction markers.
// At minimum it should be valid UTF-8 (guaranteed by String type).
let _ = clean_str.len();
}
// If scan found no matches, scan_and_clean should return the input unchanged.
if scan.matches.is_empty() {
if let Ok(ref clean_str) = cleaned {
assert_eq!(
clean_str, input,
"scan_and_clean changed content despite no matches"
);
}
}
}
});