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 ;
let findings = analyze;
for f in &findings
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 = php_core;
// WordPress (adds wp_redirect, $wpdb->query, add_action hooks, esc_html sanitizer)
let registry = wordpress;
// Laravel (adds DB::raw, Blade helpers)
let registry = laravel;
Add your own rules:
let mut registry = php_core;
registry.add_sink;
registry.sanitizers.insert;
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 ;
let findings = analyze_multi;
// 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:
[]
= { = "0.1", = ["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.