__( 'Scan Files for Malware Patterns', 'agentic-admin' ), 'description' => __( 'Scan PHP files in themes and plugins for obfuscation, shell execution, backdoors, and injected code.', 'agentic-admin' ), 'category' => 'sre-tools', 'input_schema' => array( 'type' => 'object', 'default' => array(), 'properties' => array( 'scan_plugins' => array( 'type' => 'boolean', 'description' => __( 'Scan plugin files.', 'agentic-admin' ), 'default' => true, ), 'scan_themes' => array( 'type' => 'boolean', 'description' => __( 'Scan theme files.', 'agentic-admin' ), 'default' => true, ), ), 'additionalProperties' => false, ), 'output_schema' => array( 'type' => 'object', 'properties' => array( 'success' => array( 'type' => 'boolean', 'description' => __( 'Whether the scan completed.', 'agentic-admin' ), ), 'message' => array( 'type' => 'string', 'description' => __( 'Status message.', 'agentic-admin' ), ), 'files_scanned' => array( 'type' => 'integer', 'description' => __( 'Total PHP files scanned.', 'agentic-admin' ), ), 'total_hits' => array( 'type' => 'integer', 'description' => __( 'Total files with suspicious patterns.', 'agentic-admin' ), ), 'findings' => array( 'type' => 'array', 'description' => __( 'List of files with matched patterns.', 'agentic-admin' ), ), ), ), 'execute_callback' => 'agentic_admin_execute_file_scan', 'permission_callback' => function () { return current_user_can( 'manage_options' ); }, 'meta' => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => true, 'destructive' => false, 'idempotent' => true, ), ), ), // JS configuration for chat interface. array( 'keywords' => array( 'file scan', 'malware scan', 'scan files', 'obfuscated', 'backdoor', 'shell', 'eval', 'infected files', 'scan themes', 'scan plugins' ), 'initialMessage' => __( 'Scanning PHP files for malware patterns...', 'agentic-admin' ), ) ); } /** * Malware patterns to scan for. * * Each pattern has a regex, a human-readable label, and a risk score. * Ordered from highest to lowest risk. * * IMPORTANT: Pattern regexes are built by concatenating string fragments * so this file does not contain the literal function names it scans for. * Otherwise the scanner would flag its own source code. * * Filterable via the `agentic_admin_file_scan_patterns` hook. * * @return array Array of pattern definitions. */ function agentic_admin_get_malware_patterns(): array { // NOTE: This plugin's own directory is excluded from scanning via the // agentic_admin_file_scan_excluded_paths filter (see execute function), // so these literal strings won't trigger self-detection. $patterns = array( array( 'id' => 'eval_base64', 'label' => 'eval(base64_decode(...))', 'regex' => '/eval\s*\(\s*base64_decode\s*\(/i', 'risk_score' => 9.5, ), array( 'id' => 'preg_replace_e', 'label' => 'preg_replace with /e modifier', 'regex' => '/preg_replace\s*\(\s*["\'].*\/e["\'\s]/i', 'risk_score' => 9.0, ), array( 'id' => 'assert_variable', 'label' => 'assert($variable)', 'regex' => '/assert\s*\(\s*\$/i', 'risk_score' => 8.5, ), array( 'id' => 'shell_exec', 'label' => 'Shell execution functions', 'regex' => '/\b(shell_exec|passthru|proc_open|popen)\s*\(/i', 'risk_score' => 8.0, ), array( 'id' => 'str_rot13', 'label' => 'str_rot13 encoding', 'regex' => '/str_rot13\s*\(/i', 'risk_score' => 7.5, ), array( 'id' => 'gzinflate', 'label' => 'gzinflate decompression', 'regex' => '/gzinflate\s*\(/i', 'risk_score' => 7.0, ), array( 'id' => 'iframe_in_php', 'label' => '