mirror of
https://github.com/imjasonh/rustvulncheck
synced 2026-07-16 20:43:49 +00:00
Add syn-based type tracking and golden codebase integration tests
Type tracking (type_tracker.rs): - Uses syn AST parsing to resolve variable types from function parameters, let bindings with annotations, constructor calls (Type::new()), struct literals, builder patterns, and closure parameters - Integrated into scanner to promote method-call matches from Medium to High confidence when the receiver's type is known Golden integration tests: - vulnerable_project: 4 vulnerable deps, 3 with reachable calls across multiple files (qualified calls, typed method calls, constructor-inferred types). Verifies regex dep is listed but Compiler::compile is NOT reachable. - safe_project: patched deps (hyper, smallvec) excluded, vulnerable deps (tokio, regex) listed but no symbols reachable. Reports POSSIBLY SAFE. - clean_project: no vulnerable deps at all. Reports CLEAN. 37 tests total (33 unit + 4 integration), all passing. https://claude.ai/code/session_011sdj18ZvQYbDVwEKqrWDj1
This commit is contained in:
parent
b148c8d4b8
commit
a2db0d4d15
14 changed files with 1013 additions and 83 deletions
70
tests/fixtures/golden_vuln_db.json
vendored
Normal file
70
tests/fixtures/golden_vuln_db.json
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
{
|
||||
"generated_at": "unix:1700000000",
|
||||
"entries": [
|
||||
{
|
||||
"advisory_id": "RUSTSEC-2024-0001",
|
||||
"package": "hyper",
|
||||
"title": "Lenient HTTP header parsing allows request smuggling",
|
||||
"date": "2024-01-15",
|
||||
"patched_versions": [">= 1.0.0"],
|
||||
"commit_sha": "abc123",
|
||||
"vulnerable_symbols": [
|
||||
{
|
||||
"file": "src/proto/h1/role.rs",
|
||||
"function": "hyper::proto::h1::role::Client::encode",
|
||||
"change_type": "Modified"
|
||||
},
|
||||
{
|
||||
"file": "src/proto/h1/decode.rs",
|
||||
"function": "hyper::proto::h1::decode::Decoder::decode",
|
||||
"change_type": "Modified"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"advisory_id": "RUSTSEC-2024-0010",
|
||||
"package": "smallvec",
|
||||
"title": "Buffer overflow in SmallVec::insert_many",
|
||||
"date": "2024-02-20",
|
||||
"patched_versions": [">= 1.11.0"],
|
||||
"commit_sha": "def456",
|
||||
"vulnerable_symbols": [
|
||||
{
|
||||
"file": "src/lib.rs",
|
||||
"function": "smallvec::SmallVec::insert_many",
|
||||
"change_type": "Modified"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"advisory_id": "RUSTSEC-2024-0020",
|
||||
"package": "tokio",
|
||||
"title": "Race condition in task abort",
|
||||
"date": "2024-03-01",
|
||||
"patched_versions": [">= 1.38.0"],
|
||||
"commit_sha": "ghi789",
|
||||
"vulnerable_symbols": [
|
||||
{
|
||||
"file": "src/runtime/task/mod.rs",
|
||||
"function": "tokio::runtime::task::JoinHandle::abort",
|
||||
"change_type": "Modified"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"advisory_id": "RUSTSEC-2024-0030",
|
||||
"package": "regex",
|
||||
"title": "ReDoS in regex compilation",
|
||||
"date": "2024-04-01",
|
||||
"patched_versions": [">= 1.10.0"],
|
||||
"commit_sha": "jkl012",
|
||||
"vulnerable_symbols": [
|
||||
{
|
||||
"file": "src/compile.rs",
|
||||
"function": "regex::compile::Compiler::compile",
|
||||
"change_type": "Modified"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
27
tests/fixtures/safe_project/Cargo.lock
generated
vendored
Normal file
27
tests/fixtures/safe_project/Cargo.lock
generated
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "my-safe-app"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
24
tests/fixtures/safe_project/src/handler.rs
vendored
Normal file
24
tests/fixtures/safe_project/src/handler.rs
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
//! Handler module.
|
||||
//!
|
||||
//! Uses tokio and regex, but does NOT call the vulnerable symbols.
|
||||
//! - tokio is at a vulnerable version but abort() is never called
|
||||
//! - regex is at a vulnerable version but Compiler::compile is internal and not called
|
||||
//! - hyper is at a PATCHED version (1.2.0 >= 1.0.0)
|
||||
//! - smallvec is at a PATCHED version (1.11.0 >= 1.11.0)
|
||||
|
||||
use tokio::runtime::task::JoinHandle;
|
||||
use regex::Regex;
|
||||
|
||||
pub fn run() {
|
||||
// Uses regex but NOT the vulnerable Compiler::compile — just the public API
|
||||
let re = Regex::new(r"\d+").unwrap();
|
||||
let matched = re.is_match("hello 123");
|
||||
println!("Matched: {}", matched);
|
||||
|
||||
// References JoinHandle type but never calls .abort()
|
||||
let handles: Vec<JoinHandle> = Vec::new();
|
||||
for handle in handles {
|
||||
// Just awaits, doesn't abort
|
||||
println!("waiting on handle");
|
||||
}
|
||||
}
|
||||
5
tests/fixtures/safe_project/src/main.rs
vendored
Normal file
5
tests/fixtures/safe_project/src/main.rs
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
mod handler;
|
||||
|
||||
fn main() {
|
||||
handler::run();
|
||||
}
|
||||
27
tests/fixtures/vulnerable_project/Cargo.lock
generated
vendored
Normal file
27
tests/fixtures/vulnerable_project/Cargo.lock
generated
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "my-vulnerable-app"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
6
tests/fixtures/vulnerable_project/src/main.rs
vendored
Normal file
6
tests/fixtures/vulnerable_project/src/main.rs
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
mod server;
|
||||
mod utils;
|
||||
|
||||
fn main() {
|
||||
server::run_server();
|
||||
}
|
||||
15
tests/fixtures/vulnerable_project/src/server.rs
vendored
Normal file
15
tests/fixtures/vulnerable_project/src/server.rs
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
//! Server module that uses hyper for HTTP handling.
|
||||
|
||||
use hyper::proto::h1::role::Client;
|
||||
use hyper::proto::h1::decode::Decoder;
|
||||
|
||||
pub fn run_server() {
|
||||
// Case 1: Qualified associated-function call (HIGH confidence expected)
|
||||
let client = Client::encode(raw_request);
|
||||
|
||||
// Case 2: Method call on typed variable (HIGH confidence with type tracking)
|
||||
let decoder: Decoder = Decoder::new();
|
||||
let result = decoder.decode(buf);
|
||||
|
||||
println!("Server running: {:?} {:?}", client, result);
|
||||
}
|
||||
21
tests/fixtures/vulnerable_project/src/utils.rs
vendored
Normal file
21
tests/fixtures/vulnerable_project/src/utils.rs
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
//! Utility module with additional vulnerable calls.
|
||||
|
||||
use smallvec::SmallVec;
|
||||
use tokio::runtime::task::JoinHandle;
|
||||
|
||||
pub fn process_data(items: &[u8]) {
|
||||
// Case 3: Method call on constructor-inferred type (HIGH with type tracking)
|
||||
let mut vec = SmallVec::new();
|
||||
vec.insert_many(0, items.iter().copied());
|
||||
|
||||
// Case 4: Method call on typed parameter (HIGH with type tracking)
|
||||
cancel_task(get_handle());
|
||||
}
|
||||
|
||||
fn cancel_task(handle: JoinHandle) {
|
||||
handle.abort();
|
||||
}
|
||||
|
||||
fn get_handle() -> JoinHandle {
|
||||
todo!()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue