[
  {
    "id": "VULN-AUTH-01",
    "name": "Authentication Bypass (is_admin Fallacy)",
    "section": "3.1",
    "severity": "Critical",
    "description": "Relying solely on is_admin() for authorization checks on sensitive actions.",
    "detection_logic": {
      "pattern": "Logic gate uses is_admin() as the ONLY check before sensitive actions (DB writes, file mods).",
      "false_positive_check": "Ignore if current_user_can() is present in the same block."
    },
    "remediation": "Replace or augment is_admin() with current_user_can('capability').",
    "status": "complete",
    "findings": [],
    "notes": "Verified: Sensitive actions use current_user_can() checks."
  },
  {
    "id": "VULN-AUTH-02",
    "name": "Privilege Escalation (Missing Capabilities)",
    "section": "3.2",
    "severity": "Critical",
    "description": "AJAX hooks (wp_ajax_*) that execute logic without checking user capabilities.",
    "detection_logic": {
      "context": ["add_action('wp_ajax_...')", "add_action('admin_post_...')"],
      "pattern": "Function body lacks a call to current_user_can()."
    },
    "remediation": "Add current_user_can('manage_options') (or appropriate cap) at start of function.",
    "status": "complete",
    "findings": [],
    "notes": "Verified: All AJAX handlers (handleStartConversation, handleReplyMessage, handleVote, etc.) now verify current_user_can('read')."
  },
  {
    "id": "VULN-AUTH-03",
    "name": "Insecure AJAX Registration (nopriv)",
    "section": "3.2",
    "severity": "High",
    "description": "Sensitive actions registered to wp_ajax_nopriv_ (unauthenticated users).",
    "detection_logic": {
      "pattern": "add_action('wp_ajax_nopriv_...')"
    },
    "remediation": "Remove nopriv hook if the action requires authentication. If public, ensure strict validation.",
    "status": "complete",
    "findings": [],
    "notes": "Verified: Only safe actions (like language setting) are registered for nopriv."
  },
  {
    "id": "VULN-CSRF-01",
    "name": "Missing CSRF Protection (Nonce Verification)",
    "section": "3.3",
    "severity": "High",
    "description": "Processing form data or AJAX requests without verifying a nonce.",
    "detection_logic": {
      "context": ["$_POST processing", "wp_ajax_ hooks"],
      "pattern": "Missing wp_verify_nonce(), check_admin_referer(), or check_ajax_referer()."
    },
    "remediation": "Add wp_verify_nonce( $_REQUEST['_wpnonce'], 'action_name' ).",
    "status": "complete",
    "findings": [],
    "notes": "Verified: All handlers use check_ajax_referer or wp_verify_nonce. handleMarkRead now checks nonce."
  },
  {
    "id": "VULN-CSRF-02",
    "name": "Weak Nonce (Replay Attack)",
    "section": "3.3",
    "severity": "Medium",
    "description": "Using a generic or static string for nonce action, allowing replay attacks.",
    "detection_logic": {
      "pattern": "wp_verify_nonce($n, 'generic_string') or wp_create_nonce('generic_string')."
    },
    "remediation": "Use specific action strings like 'delete_post_' . $post_id.",
    "status": "complete",
    "findings": [],
    "notes": "Verified: Nonce actions are scoped per feature (reaction/report/subscription/poll/upload/messaging). No replay-practical weak nonce issue found."
  },
  {
    "id": "VULN-REST-01",
    "name": "Open REST API Endpoint",
    "section": "3.4",
    "severity": "Critical",
    "description": "REST routes registered without a permission callback or with __return_true.",
    "detection_logic": {
      "context": ["register_rest_route"],
      "pattern": "permission_callback is missing OR set to '__return_true'."
    },
    "remediation": "Define a custom permission_callback that checks current_user_can().",
    "status": "complete",
    "findings": [],
    "notes": "Verified: REST controllers use permission callbacks."
  },
  {
    "id": "VULN-IDOR-01",
    "name": "Insecure Direct Object Reference (IDOR)",
    "section": "3.5",
    "severity": "High",
    "description": "Using user-supplied IDs (post_id, user_id) to modify data without ownership checks.",
    "detection_logic": {
      "sources": ["$_GET['id']", "$_POST['id']"],
      "sinks": ["update_user_meta", "wp_update_post", "wp_delete_post"],
      "pattern": "No check comparing input ID to get_current_user_id()."
    },
    "remediation": "Verify ownership: if ($id == get_current_user_id()) or check 'edit_others' cap.",
    "status": "complete",
    "findings": [],
    "notes": "Verified: Messaging delete/edit and Post edit/delete actions check ownership."
  },
  {
    "id": "VULN-VAL-01",
    "name": "Missing Data Validation",
    "section": "4.1",
    "severity": "Low",
    "description": "Using raw input without validating its type (email, int).",
    "detection_logic": {
      "pattern": "Usage of $_POST['email'] without is_email(), or ID without is_numeric()/absint()."
    },
    "remediation": "Wrap input in is_email(), is_int(), etc. before processing.",
    "status": "complete",
    "findings": [],
    "notes": "Verified: Inputs are cast to (int) or sanitized."
  },
  {
    "id": "VULN-VAL-02",
    "name": "Incorrect validate_file Usage",
    "section": "4.1",
    "severity": "Medium",
    "description": "Misinterpreting validate_file() return value (0 means success/safe).",
    "detection_logic": {
      "pattern": "if ( validate_file($path) ) { // treat as success }"
    },
    "remediation": "Correct logic: if ( validate_file($path) !== 0 ) { // error }.",
    "status": "complete",
    "findings": []
  },
  {
    "id": "VULN-SAN-01",
    "name": "Missing Sanitization",
    "section": "4.2",
    "severity": "Medium",
    "description": "Saving data to DB without sanitization functions.",
    "detection_logic": {
      "sinks": ["update_option", "update_post_meta"],
      "pattern": "Raw input passed to storage functions without sanitize_text_field, sanitize_key, etc."
    },
    "remediation": "Apply sanitize_text_field(), sanitize_textarea_field(), etc.",
    "status": "complete",
    "findings": [],
    "notes": "Verified: sanitize_text_field/wp_kses_post used."
  },
  {
    "id": "VULN-XSS-01",
    "name": "Reflected XSS (Output Escaping)",
    "section": "4.3",
    "severity": "High",
    "description": "Outputting user input without escaping.",
    "detection_logic": {
      "sinks": ["echo", "print", "printf"],
      "pattern": "Variable from Source reaches Sink without esc_html, esc_attr, esc_url."
    },
    "remediation": "Use esc_html(), esc_attr(), esc_url() at the point of output.",
    "status": "complete",
    "findings": [],
    "notes": "Verified: Templates use esc_html, esc_attr, esc_url."
  },
  {
    "id": "VULN-XSS-02",
    "name": "Stored XSS",
    "section": "4.3",
    "severity": "High",
    "description": "Outputting database content without escaping.",
    "detection_logic": {
      "sources": ["get_option", "get_post_meta"],
      "sinks": ["echo", "print"],
      "pattern": "DB data output without late escaping."
    },
    "remediation": "Always escape on output, even if sanitized on save.",
    "status": "complete",
    "findings": [],
    "notes": "Verified: Data is escaped on output."
  },
  {
    "id": "VULN-XSS-03",
    "name": "DOM-Based XSS",
    "section": "8.1",
    "severity": "High",
    "description": "Unsafe JavaScript DOM manipulation using user input.",
    "detection_logic": {
      "file_types": [".js"],
      "sources": ["location.hash", "location.search"],
      "sinks": ["innerHTML", "document.write"],
      "pattern": "Assigning location sources directly to innerHTML."
    },
    "remediation": "Use textContent instead of innerHTML, or sanitize using DOMPurify.",
    "status": "complete",
    "findings": [],
    "notes": "Verified: Previous frontend findings in messenger/pdf-viewer were remediated (DOM APIs now used)."
  },
  {
    "id": "VULN-XSS-04",
    "name": "Unsafe Termination Output",
    "section": "2.3",
    "severity": "Medium",
    "description": "Using die() or exit() to output unsanitized variables.",
    "detection_logic": {
      "sinks": ["die", "exit"],
      "pattern": "die($variable) where variable is unsanitized input."
    },
    "remediation": "Use die(esc_html($variable)).",
    "status": "complete",
    "findings": []
  },
  {
    "id": "VULN-I18N-01",
    "name": "Translation XSS",
    "section": "4.3",
    "severity": "Medium",
    "description": "Using _e() for strings containing variable data instead of escaping functions.",
    "detection_logic": {
      "sinks": ["_e", "__"],
      "pattern": "Using _e($var) or _e('text' . $var) instead of esc_html_e()."
    },
    "remediation": "Use esc_html_e(), esc_attr_e(), or wp_kses() on the translated string.",
    "status": "complete",
    "findings": []
  },
  {
    "id": "VULN-SQL-01",
    "name": "SQL Injection (Raw Query)",
    "section": "5.1",
    "severity": "Critical",
    "description": "Direct concatenation of variables into SQL queries.",
    "detection_logic": {
      "sinks": ["$wpdb->query", "$wpdb->get_results"],
      "pattern": "Query string contains '.' concatenation or variable interpolation ($var)."
    },
    "remediation": "Use $wpdb->prepare() with placeholders (%s, %d).",
    "status": "complete",
    "findings": [],
    "notes": "Verified: $wpdb->prepare() usage."
  },
  {
    "id": "VULN-SQL-02",
    "name": "SQL Injection (Improper Prepare)",
    "section": "5.1",
    "severity": "High",
    "description": "Passing a variable as the first argument to prepare().",
    "detection_logic": {
      "sinks": ["$wpdb->prepare"],
      "pattern": "First argument is a variable ($sql) instead of a string literal."
    },
    "remediation": "Ensure first argument is a string literal: $wpdb->prepare(\"SELECT... %s\", $var).",
    "status": "complete",
    "findings": []
  },
  {
    "id": "VULN-SQL-03",
    "name": "SQL Injection (ORDER BY)",
    "section": "5.2",
    "severity": "High",
    "description": "Dynamic ORDER BY clause without whitelisting.",
    "detection_logic": {
      "pattern": "ORDER BY $variable (prepare() %s quotes this, breaking SQL, so devs often remove prepare)."
    },
    "remediation": "Use a strict whitelist array of allowed columns.",
    "status": "complete",
    "findings": [],
    "notes": "Verified: Whitelisting used."
  },
  {
    "id": "VULN-SQL-04",
    "name": "SQL Injection (LIKE Wildcards)",
    "section": "5.2",
    "severity": "Low",
    "description": "Unescaped wildcards (%) in LIKE clauses causing DoS.",
    "detection_logic": {
      "pattern": "LIKE %s used in prepare without pre-processing input."
    },
    "remediation": "Use $wpdb->esc_like() on the input variable.",
    "status": "complete",
    "findings": []
  },
  {
    "id": "VULN-SQL-05",
    "name": "SQL Injection (IN Clause)",
    "section": "5.2",
    "severity": "High",
    "description": "Using variables directly in IN (...) clauses.",
    "detection_logic": {
      "pattern": "IN ($ids) where $ids is not prepared."
    },
    "remediation": "Use implode(',', array_map('intval', $ids)) or similar strict formatting.",
    "status": "complete",
    "findings": [],
    "notes": "Verified: array_map('intval') used."
  },
  {
    "id": "VULN-SQL-06",
    "name": "Insecure DB Configuration",
    "section": "5.3",
    "severity": "Medium",
    "description": "Changing DB charset or SQL modes.",
    "detection_logic": {
      "pattern": "Altering DB_CHARSET or disabling STRICT_TRANS_TABLES."
    },
    "remediation": "Do not alter global database configurations.",
    "status": "complete",
    "findings": []
  },
  {
    "id": "VULN-POI-01",
    "name": "PHP Object Injection",
    "section": "6.1",
    "severity": "Critical",
    "description": "Deserializing untrusted data.",
    "detection_logic": {
      "sinks": ["unserialize"],
      "pattern": "Any usage of unserialize() on variables."
    },
    "remediation": "Use json_decode() or allowed_classes option in PHP 7+.",
    "status": "complete",
    "findings": [],
    "notes": "Verified: No unserialize() found."
  },
  {
    "id": "VULN-PHAR-01",
    "name": "Phar Deserialization",
    "section": "6.2",
    "severity": "Critical",
    "description": "File operations on user-controlled paths triggering Phar deserialization.",
    "detection_logic": {
      "sinks": ["file_exists", "fopen", "file_get_contents", "is_dir", "unlink"],
      "pattern": "Path argument is user-controlled (could be 'phar://...')."
    },
    "remediation": "Validate path to ensure it does not start with phar:// or use strict whitelisting.",
    "status": "complete",
    "findings": []
  },
  {
    "id": "VULN-TYPE-01",
    "name": "PHP Type Juggling (Auth Bypass)",
    "section": "6.3",
    "severity": "High",
    "description": "Loose comparison (==) on sensitive hashes or tokens.",
    "detection_logic": {
      "pattern": "Comparison of sensitive vars (token, hash, password) using == or !=."
    },
    "remediation": "Use strict comparison (===) or hash_equals().",
    "status": "complete",
    "findings": []
  },
  {
    "id": "VULN-FILE-01",
    "name": "Unrestricted File Upload",
    "section": "7.1",
    "severity": "Critical",
    "description": "Using raw move_uploaded_file instead of WP handlers.",
    "detection_logic": {
      "sinks": ["move_uploaded_file"],
      "pattern": "Usage of raw PHP upload function."
    },
    "remediation": "Use wp_handle_upload() or wp_handle_sideload().",
    "status": "complete",
    "findings": [],
    "notes": "Verified: wp_handle_upload used."
  },
  {
    "id": "VULN-FILE-02",
    "name": "Weak MIME Validation",
    "section": "7.1",
    "severity": "High",
    "description": "Allowing arbitrary file types in upload handlers.",
    "detection_logic": {
      "context": ["wp_handle_upload"],
      "pattern": "'mimes' parameter is missing or set to allow all."
    },
    "remediation": "Strictly define allowed MIME types in the 'mimes' array.",
    "status": "complete",
    "findings": [],
    "notes": "Verified: Strict MIME whitelist enabled (no SVG)."
  },
  {
    "id": "VULN-FILE-03",
    "name": "Arbitrary File Write",
    "section": "2.3",
    "severity": "Critical",
    "description": "Writing to file system with user-controlled path/content.",
    "detection_logic": {
      "sinks": ["file_put_contents", "fwrite"],
      "pattern": "Path or Content derived from user input."
    },
    "remediation": "Use WP_Filesystem API and validate paths strictly.",
    "status": "complete",
    "findings": []
  },
  {
    "id": "VULN-FILE-04",
    "name": "Arbitrary File Deletion",
    "section": "2.3",
    "severity": "Critical",
    "description": "Deleting files based on user input.",
    "detection_logic": {
      "sinks": ["unlink"],
      "pattern": "Path argument is user-controlled."
    },
    "remediation": "Strictly whitelist allowed paths for deletion.",
    "status": "complete",
    "findings": []
  },
  {
    "id": "VULN-LFI-01",
    "name": "Local File Inclusion (LFI)",
    "section": "7.2",
    "severity": "Critical",
    "description": "Including files based on user input.",
    "detection_logic": {
      "sinks": ["include", "require", "include_once", "require_once"],
      "pattern": "Path argument contains user input variables."
    },
    "remediation": "Strict whitelist of allowed files/paths.",
    "status": "complete",
    "findings": []
  },
  {
    "id": "VULN-ZIP-01",
    "name": "Insecure Archive Extraction (Zip Slip)",
    "section": "7.2",
    "severity": "Critical",
    "description": "Using insecure unzip_file() or native ZipArchive without traversal checks.",
    "detection_logic": {
      "sinks": ["unzip_file", "ZipArchive::extractTo"],
      "pattern": "Extraction without validating filenames inside the zip for '../'."
    },
    "remediation": "Use WP_Filesystem::unzip_file() (modern versions) or validate destination paths.",
    "status": "complete",
    "findings": []
  },
  {
    "id": "VULN-REACT-01",
    "name": "React/Gutenberg Dangerous HTML",
    "section": "8.2",
    "severity": "High",
    "description": "Unsafe injection of HTML in React components.",
    "detection_logic": {
      "file_types": [".js", ".jsx", ".ts", ".tsx"],
      "pattern": "usage of dangerouslySetInnerHTML"
    },
    "remediation": "Sanitize HTML using DOMPurify or wp.sce.trustAsHtml.",
    "status": "complete",
    "findings": []
  },
  {
    "id": "VULN-REACT-02",
    "name": "React Attribute Injection",
    "section": "8.2",
    "severity": "Medium",
    "description": "Allowing javascript: URIs in React attributes.",
    "detection_logic": {
      "file_types": [".js", ".jsx"],
      "pattern": "href={...} or src={...} where variable is not sanitized."
    },
    "remediation": "Validate URL protocol to ensure it is http/https/mailto.",
    "status": "complete",
    "findings": []
  },
  {
    "id": "VULN-REDIR-01",
    "name": "Open Redirect",
    "section": "8.3",
    "severity": "Medium",
    "description": "Redirecting users to arbitrary URLs.",
    "detection_logic": {
      "sinks": ["wp_redirect"],
      "pattern": "Argument is user-controlled."
    },
    "remediation": "Use wp_safe_redirect() which enforces local domain or allowed whitelist.",
    "status": "complete",
    "findings": [],
    "notes": "Verified: wp_safe_redirect() is used throughout."
  },
  {
    "id": "VULN-SSRF-01",
    "name": "Server-Side Request Forgery",
    "section": "9.1",
    "severity": "Medium",
    "description": "Making HTTP requests to user-supplied URLs.",
    "detection_logic": {
      "sinks": ["wp_remote_get", "wp_remote_post", "curl_exec"],
      "pattern": "URL argument is user-controlled."
    },
    "remediation": "Use wp_safe_remote_get().",
    "status": "complete",
    "findings": [],
    "notes": "Verified: Embeds use strict domain whitelist."
  },
  {
    "id": "VULN-RCE-01",
    "name": "Remote Code Execution (Callback)",
    "section": "2.3",
    "severity": "Critical",
    "description": "Executing arbitrary functions via user input.",
    "detection_logic": {
      "sinks": ["call_user_func", "call_user_func_array"],
      "pattern": "First argument is user-controlled input."
    },
    "remediation": "Allow only a strict whitelist of function names.",
    "status": "complete",
    "findings": []
  },
  {
    "id": "VULN-INFO-01",
    "name": "Sensitive Info Exposure (Debug)",
    "section": "10.2",
    "severity": "Low",
    "description": "Debug functions left in production code.",
    "detection_logic": {
      "pattern": "Usage of print_r(), var_dump(), or error_log() printing full objects."
    },
    "remediation": "Remove debug code.",
    "status": "complete",
    "findings": [
      {
        "file": "includes/class-presszone-forum-admin-bar.php",
        "line": 140,
        "snippet": "error_log('[Forum Press Zone] System Refresh FAILED: Database operation error');",
        "context": "Unconditional error_log() call.",
        "risk": "Low. Log noise."
      },
      {
        "file": "includes/class-presszone-forum-plugin.php",
        "line": 911,
        "snippet": "error_log('Forum Press Zone: Failed to write custom CSS file to ' . basename($customCssFile));",
        "context": "Debug logging retained (path now basename-only, reduced disclosure).",
        "risk": "Low. Operational debug logging remains in runtime paths."
      },
      {
        "file": "includes/class-presszone-forum-notifications.php",
        "line": 168,
        "snippet": "error_log(sprintf('[Forum Press Zone] getUnreadCount query: %s | result: %s | last_error: %s', ...));",
        "context": "Logs full SQL query + DB error details in WP_DEBUG.",
        "risk": "Low. Can expose internal schema/query details in logs."
      },
      {
        "file": "includes/class-presszone-forum-template-loader.php",
        "line": 129,
        "snippet": "error_log('[FPZ TemplateLoader] load() called - template: ' . $templateName . ' | fullPageMode: ' . ...);",
        "context": "Verbose debug logs include runtime template details.",
        "risk": "Low. Increases sensitive operational telemetry in logs."
      },
      {
        "file": "includes/class-presszone-forum-post-creator.php",
        "line": 560,
        "snippet": "error_log('FPZ Word Filter: BLOCKED for pattern: \"' . $word . '\" in content: \"' . mb_substr($content, 0, 100) . '...\"');",
        "context": "Logs excerpt of user-submitted content.",
        "risk": "Low. Potential PII leakage into server logs."
      },
      {
        "file": "includes/class-presszone-forum-activator.php",
        "line": 55,
        "snippet": "error_log('[FPZ Activator] repairTables() - Starting table creation...');",
        "context": "Multiple unconditional lifecycle logs in activation path.",
        "risk": "Low. Production log noise and environment detail leakage."
      }
    ],
    "notes": "Expanded findings: logging is widespread; most is low severity but should be gated behind strict debug controls and sanitized/minimized."
  },
  {
    "id": "VULN-XSS-05",
    "name": "Admin Error Rendering XSS",
    "section": "8.1",
    "severity": "Medium",
    "description": "Admin UI renders API error messages with innerHTML, allowing HTML interpretation in privileged context.",
    "detection_logic": {
      "file_types": [".js"],
      "sources": ["API error.message"],
      "sinks": ["innerHTML"],
      "pattern": "innerHTML assignment containing error.message without escaping/textContent."
    },
    "remediation": "Render error messages with textContent or sanitize before insertion.",
    "status": "complete",
    "findings": [
      {
        "file": "admin/src-vanilla/pages/forum-manager.js",
        "line": 679,
        "snippet": "container.innerHTML = `<div class=\"presszone-forum-error\">${error.message}</div>`;",
        "context": "Moderators tab error state.",
        "risk": "Medium"
      },
      {
        "file": "admin/src-vanilla/pages/forum-manager.js",
        "line": 812,
        "snippet": "container.innerHTML = `<div class=\"presszone-forum-error\">${error.message}</div>`;",
        "context": "Existing-forum moderators error state.",
        "risk": "Medium"
      },
      {
        "file": "admin/src-vanilla/pages/bans.js",
        "line": 670,
        "snippet": "container.innerHTML = '<p class=\"presszone-forum-error\">' + __('Failed to load.', 'forum-press-zone') + ' ' + error.message + '</p>';",
        "context": "Infraction list load error state.",
        "risk": "Medium"
      }
    ],
    "notes": "New finding discovered during JS source-to-sink review."
  },
  {
    "id": "VULN-CODE-01",
    "name": "Commented-Out Security Checks",
    "section": "10.2",
    "severity": "Medium",
    "description": "Security logic (like current_user_can) that has been commented out.",
    "detection_logic": {
      "pattern": "//.*current_user_can|/*.*current_user_can"
    },
    "remediation": "Uncomment security checks or remove dead code.",
    "status": "complete",
    "findings": []
  },
  {
    "id": "VULN-DEP-01",
    "name": "Vulnerable Dependencies",
    "section": "10.2",
    "severity": "Medium",
    "description": "Outdated libraries in composer.lock.",
    "detection_logic": {
      "file": "composer.lock",
      "pattern": "Check package versions against known vulnerability database."
    },
    "remediation": "Run composer update.",
    "status": "complete",
    "findings": [],
    "notes": "No composer.lock found"
  }
]
