#![cfg(feature = "rust-lang")]
use pyrograph::{analyze, parse::parse_rust};
fn findings(source: &str) -> usize {
let graph = parse_rust(source, "build.rs").unwrap();
analyze(&graph).unwrap().len()
}
macro_rules! tp {
($name:ident, $src:expr) => {
#[test]
fn $name() {
assert!(findings($src) > 0, "expected a taint finding");
}
};
}
macro_rules! fp {
($name:ident, $src:expr) => {
#[test]
fn $name() {
assert_eq!(findings($src), 0, "expected no taint findings");
}
};
}
tp!(rust_tp_if_let, r#"
fn main() {
if let Ok(token) = std::env::var("TOKEN") {
reqwest::get(token);
}
}
"#);
fp!(rust_fp_if_let, r#"
fn main() {
if let Ok(url) = Result::<String, ()>::Ok("https://example.com".into()) {
let c = reqwest::Client::new(); c.get(url);
}
}
"#);
tp!(rust_tp_match_arms, r#"
fn main() {
match std::env::var("TOKEN") {
Ok(v) => reqwest::get(v),
_ => {}
}
}
"#);
fp!(rust_fp_match_arms, r#"
fn main() {
match "safe" {
url => reqwest::get(url),
}
}
"#);
tp!(rust_tp_closures, r#"
fn main() {
let f = || { reqwest::get(std::env::var("TOKEN").unwrap()) };
f();
}
"#);
fp!(rust_fp_closures, r#"
fn main() {
let f = || { let c = reqwest::Client::new(); c.get("https://example.com"); };
f();
}
"#);
tp!(rust_tp_for_loops, r#"
fn main() {
for (_, v) in std::env::vars() {
reqwest::get(v);
}
}
"#);
fp!(rust_fp_for_loops, r#"
fn main() {
for url in ["https://example.com"] {
let c = reqwest::Client::new(); c.get(url);
}
}
"#);
tp!(rust_tp_while_let, r#"
fn main() {
let mut it = Some(std::env::var("TOKEN").unwrap()).into_iter();
while let Some(v) = it.next() {
reqwest::get(v);
}
}
"#);
fp!(rust_fp_while_let, r#"
fn main() {
let mut it = Some("safe".to_string()).into_iter();
while let Some(v) = it.next() {
reqwest::get(v);
}
}
"#);
tp!(rust_tp_try_operator, r#"
fn main() -> Result<(), std::io::Error> {
let creds = std::fs::read_to_string("/home/user/.cargo/credentials")?;
reqwest::get(creds);
Ok(())
}
"#);
fp!(rust_fp_try_operator, r#"
fn main() -> Result<(), std::io::Error> {
let data = std::fs::read_to_string("/tmp/port")?;
let port = data.parse::<i32>()?;
reqwest::get(port.to_string());
Ok(())
}
"#);
tp!(rust_tp_struct_fields, r#"
struct Payload { data: String }
fn main() {
let token = std::env::var("TOKEN").unwrap();
let p = Payload { data: token };
reqwest::get(p.data);
}
"#);
fp!(rust_fp_struct_fields, r#"
struct Payload { data: String }
fn main() {
let p = Payload { data: "safe".into() };
reqwest::get(p.data);
}
"#);
tp!(rust_tp_tuple_indexing, r#"
fn main() {
let t = (std::env::var("TOKEN").unwrap(), 1);
reqwest::get(t.0);
}
"#);
fp!(rust_fp_tuple_indexing, r#"
fn main() {
let t = ("safe".into(), 1);
reqwest::get(t.0);
}
"#);
tp!(rust_tp_method_chains, r#"
fn main() {
let secret = std::env::var("SECRET").unwrap();
std::process::Command::new("sh").arg("-c").arg(secret).spawn().unwrap();
}
"#);
fp!(rust_fp_method_chains, r#"
fn main() {
std::process::Command::new("sh").arg("-c").arg("echo ok").spawn().unwrap();
}
"#);
tp!(rust_tp_trait_method_calls, r#"
trait Exfil { fn run(&self); }
struct S;
impl Exfil for S {
fn run(&self) {
let token = std::env::var("TOKEN").unwrap();
reqwest::get(token);
}
}
fn main() { S.run(); }
"#);
fp!(rust_fp_trait_method_calls, r#"
trait Safe { fn run(&self); }
struct S;
impl Safe for S {
fn run(&self) {
reqwest::get("safe".to_string());
}
}
fn main() { S.run(); }
"#);
tp!(rust_tp_async_await, r#"
async fn main() {
let token = std::env::var("TOKEN").unwrap();
let f = async { token };
reqwest::get(f.await);
}
"#);
fp!(rust_fp_async_await, r#"
async fn main() {
let f = async { "safe".to_string() };
reqwest::get(f.await);
}
"#);
tp!(rust_tp_macro_invocations, r#"
macro_rules! exfil { ($e:expr) => { $e }; }
fn main() {
exfil!(reqwest::get(std::env::var("TOKEN").unwrap()));
}
"#);
fp!(rust_fp_macro_invocations, r#"
macro_rules! ok { ($e:expr) => { $e }; }
fn main() {
ok!(reqwest::get("safe".to_string()));
}
"#);
tp!(rust_tp_unsafe_blocks, r#"
fn main() {
unsafe {
let token = std::env::var("TOKEN").unwrap();
reqwest::get(token);
}
}
"#);
fp!(rust_fp_unsafe_blocks, r#"
fn main() {
unsafe {
reqwest::get("safe".to_string());
}
}
"#);
tp!(rust_tp_impl_blocks, r#"
struct S;
impl S {
const PATH: &str = "/home/user/.cargo/credentials";
}
fn main() {
let creds = std::fs::read_to_string(S::PATH).unwrap();
reqwest::get(creds);
}
"#);
fp!(rust_fp_impl_blocks, r#"
struct S;
impl S {
fn msg() -> String { "safe".into() }
}
fn main() {
reqwest::get(S::msg());
}
"#);
tp!(rust_tp_array_indexing, r#"
fn main() {
let arr = [std::env::var("TOKEN").unwrap()];
reqwest::get(arr[0].clone());
}
"#);
fp!(rust_fp_array_indexing, r#"
fn main() {
let arr = ["safe".into()];
reqwest::get(arr[0].clone());
}
"#);
tp!(rust_tp_cast_expressions, r#"
fn main() {
reqwest::get(std::env::var("TOKEN").unwrap() as String);
}
"#);
fp!(rust_fp_cast_expressions, r#"
fn main() {
reqwest::get("safe".to_string() as String);
}
"#);
tp!(rust_tp_binary_operations, r#"
fn main() {
let token = std::env::var("TOKEN").unwrap();
reqwest::get("prefix".to_string() + &token);
}
"#);
fp!(rust_fp_binary_operations, r#"
fn main() {
reqwest::get("safe1".to_string() + "safe2");
}
"#);
tp!(rust_tp_return_expressions, r#"
fn steal() -> String {
return std::env::var("TOKEN").unwrap();
}
fn main() {
reqwest::get(steal());
}
"#);
fp!(rust_fp_return_expressions, r#"
fn safe() -> String {
return "safe".into();
}
fn main() {
reqwest::get(safe());
}
"#);
tp!(rust_tp_reference, r#"
fn main() {
let token = std::env::var("TOKEN").unwrap();
reqwest::get((&token).to_string());
}
"#);
fp!(rust_fp_reference, r#"
fn main() {
let s = "safe".to_string();
reqwest::get((&s).to_string());
}
"#);
tp!(rust_tp_loop_expressions, r#"
fn main() {
loop {
let token = std::env::var("TOKEN").unwrap();
reqwest::get(token);
break;
}
}
"#);
fp!(rust_fp_loop_expressions, r#"
fn main() {
loop {
reqwest::get("safe".to_string());
break;
}
}
"#);
tp!(rust_tp_try_blocks, r#"
fn main() {
let creds: Result<String, std::io::Error> = try {
std::fs::read_to_string("/home/user/.cargo/credentials")?
};
reqwest::get(creds.unwrap());
}
"#);
fp!(rust_fp_try_blocks, r#"
fn main() {
let data: Result<String, std::io::Error> = try {
std::fs::read_to_string("/tmp/ok.txt")?
};
let n = data.unwrap().parse::<i32>().unwrap();
reqwest::get(n.to_string());
}
"#);
tp!(rust_tp_const_blocks, r#"
fn main() {
let path = const { "/home/user/.cargo/credentials" };
let creds = std::fs::read_to_string(path).unwrap();
reqwest::get(creds);
}
"#);
fp!(rust_fp_const_blocks, r#"
fn main() {
let path = const { "/tmp/ok.txt" };
let data = std::fs::read_to_string(path).unwrap().parse::<i32>().unwrap();
reqwest::get(data.to_string());
}
"#);
tp!(rust_tp_field_access_chain, r#"
struct Outer { inner: Inner }
struct Inner { val: String }
fn main() {
let o = Outer { inner: Inner { val: std::env::var("TOKEN").unwrap() } };
reqwest::get(o.inner.val);
}
"#);
fp!(rust_fp_field_access_chain, r#"
struct Outer { inner: Inner }
struct Inner { val: String }
fn main() {
let o = Outer { inner: Inner { val: "safe".into() } };
reqwest::get(o.inner.val);
}
"#);
tp!(rust_tp_tuple_destructure_let, r#"
fn main() {
let (token, _) = (std::env::var("TOKEN").unwrap(), 42);
reqwest::get(token);
}
"#);
fp!(rust_fp_tuple_destructure_let, r#"
fn main() {
let (a, _) = ("safe".into(), 42);
reqwest::get(a);
}
"#);
tp!(rust_tp_assign_expressions, r#"
fn main() {
let mut x = String::new();
x = std::env::var("TOKEN").unwrap();
reqwest::get(x);
}
"#);
fp!(rust_fp_assign_expressions, r#"
fn main() {
let mut x = String::new();
x = "safe".into();
reqwest::get(x);
}
"#);