use crate::evidence::Confidence; use crate::patterns::{Pattern, PatternCategory, PatternTier, Severity}; /// PHP AST patterns. /// /// Taint rules cover `system`/`exec`/`passthru`/`shell_exec` (command /// injection), `echo`/`print` (XSS sinks), and `mysqli_query`/`pg_query` /// (SQL sinks). AST patterns here focus on **eval**, **deserialization**, /// **deprecated dangerous functions**, **include with variable**, and /// **SQL concatenation** (Tier B). pub const PATTERNS: &[Pattern] = &[ // ── Tier A: Code execution ───────────────────────────────────────── Pattern { id: "php.code_exec.eval", description: "eval() runs dynamic code", query: r#"(function_call_expression function: (name) @n (#eq? @n "eval")) @vuln"#, severity: Severity::High, tier: PatternTier::A, category: PatternCategory::CodeExec, confidence: Confidence::High, }, Pattern { id: "php.code_exec.create_function", description: "create_function() is a deprecated eval-like constructor", query: r#"(function_call_expression function: (name) @n (#eq? @n "create_function")) @vuln"#, severity: Severity::High, tier: PatternTier::A, category: PatternCategory::CodeExec, confidence: Confidence::High, }, Pattern { id: "php.code_exec.preg_replace_e", description: "preg_replace with /e modifier executes code via regex", query: r#"(function_call_expression function: (name) @n (#eq? @n "preg_replace") arguments: (arguments (argument (string) @pat (#match? @pat "/[^/]*/[a-zA-Z]*e")))) @vuln"#, severity: Severity::High, tier: PatternTier::A, category: PatternCategory::CodeExec, confidence: Confidence::High, }, Pattern { id: "php.code_exec.assert_string", description: "assert() with a string argument evaluates PHP code", query: r#"(function_call_expression function: (name) @n (#eq? @n "assert") arguments: (arguments (argument (string) @code))) @vuln"#, severity: Severity::High, tier: PatternTier::A, category: PatternCategory::CodeExec, confidence: Confidence::High, }, // ── Tier A: Command execution ────────────────────────────────────── Pattern { id: "php.cmdi.system", description: "system/shell_exec/exec/passthru runs a shell command", query: r#"(function_call_expression function: (name) @n (#match? @n "^(system|shell_exec|exec|passthru|proc_open|popen)$")) @vuln"#, severity: Severity::High, tier: PatternTier::A, category: PatternCategory::CommandExec, confidence: Confidence::High, }, // ── Tier A: Deserialization ──────────────────────────────────────── Pattern { id: "php.deser.unserialize", description: "unserialize() enables PHP object injection", query: r#"(function_call_expression function: (name) @n (#eq? @n "unserialize")) @vuln"#, severity: Severity::High, tier: PatternTier::A, category: PatternCategory::Deserialization, confidence: Confidence::High, }, // ── Tier B: SQL injection (concatenation heuristic) ──────────────── Pattern { id: "php.sqli.query_concat", description: "mysql_query/mysqli_query with concatenated SQL string", query: r#"(function_call_expression function: (name) @n (#match? @n "^(mysql_query|mysqli_query)$") arguments: (arguments (argument (binary_expression) @concat))) @vuln"#, severity: Severity::Medium, tier: PatternTier::B, category: PatternCategory::SqlInjection, confidence: Confidence::Medium, }, // ── Tier B: Path traversal (include with variable) ───────────────── Pattern { id: "php.path.include_variable", description: "include/require with a variable path is a file-inclusion vulnerability", query: r#"(include_expression (variable_name)) @vuln"#, severity: Severity::High, tier: PatternTier::B, category: PatternCategory::PathTraversal, confidence: Confidence::Medium, }, // ── Tier A: Crypto ───────────────────────────────────────────────── Pattern { id: "php.crypto.md5", description: "md5() is a weak hash function", query: r#"(function_call_expression function: (name) @n (#eq? @n "md5")) @vuln"#, severity: Severity::Low, tier: PatternTier::A, category: PatternCategory::Crypto, confidence: Confidence::Medium, }, Pattern { id: "php.crypto.sha1", description: "sha1() is a weak hash function", query: r#"(function_call_expression function: (name) @n (#eq? @n "sha1")) @vuln"#, severity: Severity::Low, tier: PatternTier::A, category: PatternCategory::Crypto, confidence: Confidence::Medium, }, Pattern { id: "php.crypto.rand", description: "rand()/mt_rand() is not cryptographically secure", query: r#"(function_call_expression function: (name) @n (#match? @n "^(rand|mt_rand)$")) @vuln"#, severity: Severity::Low, tier: PatternTier::A, category: PatternCategory::Crypto, confidence: Confidence::Medium, }, ];