phptaint 0.2.0

Security-focused PHP lexer, parser, AST, and configurable taint analysis engine
Documentation

phptaint

Lex, parse, and taint-analyze PHP source code. Tracks data flow from sources ($_GET, $_POST) to sinks (eval, exec, echo) with configurable rules. Ships with WordPress and Laravel presets.

use phptaint::taint::{TaintRegistry, analyze};

let findings = analyze("plugin.php", r#"<?php
$cmd = $_GET['cmd'];
eval($cmd);
?>"#, &TaintRegistry::php_core());

for f in &findings {
    println!("[{}] {} at line {}", f.category, f.description, f.line);
}

Configurable rules

The taint engine is driven by a TaintRegistry that defines sinks, sanitizers, and framework hooks. Three presets ship with the crate:

// PHP builtins only (eval, exec, echo, file ops)
let registry = TaintRegistry::php_core();

// WordPress (adds wp_redirect, $wpdb->query, add_action hooks, esc_html sanitizer)
let registry = TaintRegistry::wordpress();

// Laravel (adds DB::raw, Blade helpers)
let registry = TaintRegistry::laravel();

Add your own rules:

let mut registry = TaintRegistry::php_core();
registry.add_sink("my_dangerous_func", &[], "Custom Vuln", Severity::High);
registry.sanitizers.insert("my_sanitizer".into());

What the parser handles

Assignments, function calls, method calls, static calls, closures, classes, if/else, foreach, while, try/catch, switch, ternary, null coalesce, string interpolation, array literals ([]), nullsafe operator (?->), arrow functions (fn() =>), and WordPress hook callbacks (add_action with inline closures).

It does not handle arithmetic operators, bitwise ops, match expressions, enums, or readonly classes. These don't affect taint flow so they're skipped intentionally.

Multi-file analysis

use phptaint::taint::{TaintRegistry, analyze_multi};

let findings = analyze_multi(&[
    ("a.php", "<?php function run($c) { exec($c); } ?>"),
    ("b.php", "<?php run($_GET['cmd']); ?>"),
], &TaintRegistry::php_core());
// Detects: tainted data flows from b.php through run() to exec() in a.php

No forced dependencies

secfinding is an optional dependency. phptaint defines its own Severity enum. Enable the secfinding feature for From/Into conversions:

[dependencies]
phptaint = { version = "0.1", features = ["secfinding"] }

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