Skip to content

santhsecurity/respdiff

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

respdiff

Trait-based differential response analysis and probe learning for HTTP scanning. It compares HTTP responses to find meaningful differences and automatically discovers injection gates from probe histories.

use std::time::Duration;
use respdiff::{ResponseSnapshot, compare_responses};

let baseline = ResponseSnapshot::new(
    200,
    vec![("Server", "nginx")],
    "hello world"
).with_elapsed(Duration::from_millis(50));

let current = ResponseSnapshot::new(
    500,
    vec![("Server", "nginx"), ("X-Error", "1")],
    "internal error"
).with_elapsed(Duration::from_millis(60));

let diff = compare_responses(&baseline, &current);

if diff.has_differences() {
    println!("Status changed: {}", diff.status_changed);
    println!("New headers: {:?}", diff.new_headers);
    println!("Body similarity: {:.2}", diff.body_similarity);
}

Why this exists

Scanners need to know if a payload actually changed the server's behavior. A raw text diff of two HTTP responses is useless because dynamic tokens, timestamps, and randomized content change on every request. respdiff understands HTTP semantics. It diffs headers intelligently, calculates body similarity using Jaccard index, and evaluates timing changes against configurable thresholds.

Differential policies

Configure the thresholds for what constitutes a meaningful difference.

use respdiff::{DiffPolicy, is_differential_match_with_policy};

let policy = DiffPolicy {
    timing_threshold_ms: 200,
    similarity_threshold: 0.85,
};

let is_match = is_differential_match_with_policy(&diff, &policy);

Probe learning

The DifferentialLearner analyzes a history of observations to identify which input properties act as gates and which ones are injectable. It generates new variants based on successful shapes.

use std::time::Duration;
use respdiff::{DifferentialLearner, ProbeObservation};

let mut learner = DifferentialLearner::new().with_analyze_every(50);

learner.record(
    [("action", "run"), ("payload", "test")],
    ProbeObservation::matched(Duration::from_millis(5), ["code"])
);

let variants = learner.generate_variants(&["alert(1)"]);
for variant in variants {
    println!("Try properties {:?} because {}", variant.properties, variant.reason);
}

Contributing

Pull requests are welcome. There is no such thing as a perfect crate. If you find a bug, a better API, or just a rough edge, open a PR. We review quickly.

License

MIT. Copyright 2026 CORUM COLLECTIVE LLC.

crates.io docs.rs

About

Trait-based differential response analysis and probe learning for HTTP scanning.

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages