Debug Log Manager <= 2.5.0 - Unauthenticated Improper Output Neutralization for Logs via log_js_errors AJAX Action
Description
The Debug Log Manager – Conveniently Monitor and Inspect Errors plugin for WordPress is vulnerable to Improper Output Neutralization for Logs in all versions up to, and including, 2.5.0. This is due to the `log_js_errors()` AJAX handler being registered for unauthenticated users via `wp_ajax_nopriv_log_js_errors` and gated only by a nonce that is publicly disclosed in every front-end page's HTML through `wp_localize_script()` whenever JavaScript error logging is enabled, providing no real authorization barrier. This makes it possible for unauthenticated attackers to inject arbitrary forged entries into the site's WordPress debug log by supplying attacker-controlled values for the `message`, `script`, `lineNo`, `columnNo`, and `pageUrl` fields — enabling spoofing of error and incident records, obscuring malicious activity within fabricated log noise, and misleading administrators who rely on the log for triage. This vulnerability is only exploitable when the plugin's JavaScript error logging feature is enabled, as the requisite nonce is only published into the page HTML under that condition.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=2.5.0What Changed in the Fix
Changes introduced in v2.5.1
Source Code
WordPress.org SVN# Research Plan: CVE-2026-9016 - Unauthenticated Log Injection in Debug Log Manager ## 1. Vulnerability Summary The **Debug Log Manager** plugin (<= 2.5.0) contains a vulnerability that allows unauthenticated attackers to inject arbitrary entries into the WordPress debug log. This occurs because th…
Show full research plan
Research Plan: CVE-2026-9016 - Unauthenticated Log Injection in Debug Log Manager
1. Vulnerability Summary
The Debug Log Manager plugin (<= 2.5.0) contains a vulnerability that allows unauthenticated attackers to inject arbitrary entries into the WordPress debug log. This occurs because the log_js_errors() AJAX handler is registered for unauthenticated users (wp_ajax_nopriv_log_js_errors) and relies on a security nonce that is leaked in the front-end HTML source code when the "JavaScript Error Logging" feature is enabled. An attacker can use this to spoof error reports, create log noise to hide malicious activity, or mislead administrators.
2. Attack Vector Analysis
- Endpoint:
http://<target>/wp-admin/admin-ajax.php - Action:
log_js_errors(passed via theactionURL parameter) - Method:
POST - Authentication: None required (uses
wp_ajax_nopriv_) - Precondition: The plugin's "JavaScript Error Logging" feature must be enabled.
- Vulnerable Parameter: The entire JSON-encoded body of the POST request, specifically the
message,script,lineNo,columnNo, andpageUrlfields.
3. Code Flow
- Hook Registration: The plugin likely registers the AJAX actions in
classes/class-ajax.php(inferred from autoloader pattern andassets/js/public.jsfunctionality):add_action('wp_ajax_log_js_errors', 'log_js_errors');add_action('wp_ajax_nopriv_log_js_errors', 'log_js_errors');
- Nonce Exposure: In a class handling front-end assets (likely
classes/class-public.php), the plugin useswp_localize_script()to pass thedlmVarsobject toassets/js/public.js. This object includesjsErrorLogging.nonce. - Trigger: When a JS error occurs or when an attacker manually invokes the request,
assets/js/public.jssends a POST request toadmin-ajax.php. - Processing: The
log_js_errors()handler reads the input (likely viaphp://inputas it's sent asapplication/json), verifies the nonce, and then formats a string containing the user-supplied fields. - Sink: This formatted string is passed to
error_log(), which writes it to the site's debug log file (the location of which is managed by the plugin inclasses/class-debug-log.php).
4. Nonce Acquisition Strategy
The nonce is unique to the user session (for unauthenticated users, uid=0) and the log_js_errors action. It is exposed in the HTML of any front-end page when JS error logging is active.
- Check Status: Use WP-CLI to ensure JS logging is enabled.
wp option get debug_log_manager_js_error_logging(Guessing the option name; search for "js_error" in options if this fails).
- Access Page: Navigate to the homepage or any public page.
- Extract Nonce: Use the
browser_evaltool to retrieve the nonce from thedlmVarsglobal object.- JS Command:
window.dlmVars?.jsErrorLogging?.nonce
- JS Command:
5. Exploitation Strategy
- Setup: Enable the plugin's debug logging and JavaScript error logging features.
- Target URL:
http://localhost:8080/wp-admin/admin-ajax.php?action=log_js_errors - Payload: A JSON object containing the leaked nonce and malicious log content.
- Request Construction:
- Method:
POST - Content-Type:
application/json - Body:
{"nonce":"[LEAKED_NONCE]","message":"PHP Fatal error: Uncaught Error: Call to undefined function backdoored_function() in /var/www/html/wp-content/plugins/akismet/akismet.php:123","script":"https://example.com/malicious.js","lineNo":666,"columnNo":13,"pageUrl":"/wp-admin/","type":"front end"}
- Method:
- Execution: Use
http_requestto send the payload.
6. Test Data Setup
- Plugin Activation: Ensure
debug-log-manageris active. - Enable Features:
- Use WP-CLI to enable the plugin's main logging:
wp eval "update_option('debug_log_manager', ['status' => 'enabled', 'on' => date('Y-m-d H:i:s')]);" - Enable JS error logging:
wp option update debug_log_manager_js_error_logging "enabled"(Verify actual option name if necessary).
- Use WP-CLI to enable the plugin's main logging:
- Log Path: Identify the custom log path:
wp option get debug_log_manager_file_path.
7. Expected Results
- The AJAX request should return a
200 OKor a success JSON response (e.g.,{"success":true}). - The site's debug log file (found at the path retrieved in Step 6) will contain a new entry incorporating the strings provided in the
message,script, andpageUrlfields.
8. Verification Steps
- Check Log Content: Read the last few lines of the debug log.
wp eval "echo file_get_contents(get_option('debug_log_manager_file_path'));" | tail -n 5
- Confirm Injection: Verify that the string
"backdoored_function()"or the custommessagevalue appears exactly as injected.
9. Alternative Approaches
- URI Encoding: If a raw JSON POST fails, try URI-encoding the body, as the JS in
assets/js/public.jsusesencodeURI(JSON.stringify(data)). - Parameter Variation: Try sending the data via standard
application/x-www-form-urlencodedifapplication/jsonis not correctly handled by the server. - XSS Check: Since the plugin displays log entries in the admin dashboard (
classes/class-debug-log.php), check if injecting<script>alert(1)</script>into themessagefield leads to Stored XSS when viewing the "Debug Log" menu inwp-admin.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.