CVE-2025-12168

Phrase TMS Integration for WordPress <= 4.7.5 - Missing Authorization to Authenticated (Subscriber+) Log Deletion

mediumMissing Authorization
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
4.7.6
Patched in
1d
Time to patch

Description

The Phrase TMS Integration for WordPress plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the 'wp_ajax_delete_log' AJAX endpoint in all versions up to, and including, 4.7.5. This makes it possible for authenticated attackers, with Subscriber-level access and above, to delete log files.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=4.7.5
PublishedJanuary 16, 2026
Last updatedJanuary 17, 2026
Affected pluginmemsource-connector

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan outlines the steps required to analyze and exploit the **CVE-2025-12168** vulnerability in the Phrase TMS Integration for WordPress (memsource-connector) plugin. ## 1. Vulnerability Summary The "Phrase TMS Integration for WordPress" plugin (<= 4.7.5) fails to implement proper aut…

Show full research plan

This research plan outlines the steps required to analyze and exploit the CVE-2025-12168 vulnerability in the Phrase TMS Integration for WordPress (memsource-connector) plugin.

1. Vulnerability Summary

The "Phrase TMS Integration for WordPress" plugin (<= 4.7.5) fails to implement proper authorization checks on its AJAX endpoint wp_ajax_delete_log. While the endpoint is intended for administrative use, it only checks for an authenticated session but lacks a current_user_can() check (e.g., for manage_options). This allows any authenticated user, including those with Subscriber-level roles, to trigger the deletion of log files managed by the plugin.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: delete_log
  • Method: POST
  • Parameters:
    • action: delete_log (Required)
    • log: The identifier or filename of the log to be deleted (Inferred - to be verified in source).
    • _ajax_nonce or similar nonce parameter (Required).
  • Authentication: Authenticated (Subscriber or higher).
  • Preconditions: The plugin must have generated at least one log file, and the attacker must obtain a valid nonce.

3. Code Flow

  1. Registration: The plugin registers the AJAX handler in its admin or main class.
    • Code Location (likely): src/MemsourceConnector/Admin/Admin.php or includes/class-memsource-connector-admin.php.
    • Hook: add_action('wp_ajax_delete_log', array($this, 'delete_log'));
  2. Execution: When a request is sent to admin-ajax.php?action=delete_log:
    • admin-ajax.php executes the registered callback (e.g., delete_log()).
    • The callback likely calls check_ajax_referer('memsource_nonce', 'nonce') (Action/Parameter names to be confirmed).
    • The Bug: The callback proceeds to delete a file via unlink() or a similar filesystem function without calling current_user_can('manage_options').
  3. Sink: The unlink() function is called on a path constructed from the log parameter.

4. Nonce Acquisition Strategy

The plugin likely localizes a nonce for its administrative interface. Even though a Subscriber cannot access the plugin's settings page, the nonce may be enqueued on all admin pages (including the Dashboard) or may be accessible if the Subscriber can load a specific admin context.

  1. Identify Localization: Search for wp_localize_script in the plugin code to find the JS object name and nonce key.
    • Likely Object: memsource_admin or phrase_tms_vars.
    • Likely Nonce Action: memsource_nonce or phrase_nonce.
  2. Creation of Access Point: If the script is only loaded on specific admin pages, a Subscriber might still be able to view the Dashboard (/wp-admin/index.php).
  3. Extraction via Browser:
    • Login as Subscriber.
    • Navigate to /wp-admin/index.php.
    • Execute: browser_eval("window.memsource_admin?.nonce") (Replace with actual variable found during analysis).

5. Exploitation Strategy

Step 1: Discover Log Files

Before deletion, we must identify a valid log file. The plugin typically stores logs in wp-content/uploads/memsource/logs/ or within the plugin folder.
Action: Use wp_cli to list the contents of the log directory to identify a target filename.

Step 2: Obtain Nonce

As a Subscriber, extract the nonce using the browser_eval method described above.

Step 3: Trigger Deletion

Send the malicious AJAX request.

Request Template:

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    action=delete_log&nonce=[NONCE_VALUE]&log=[LOG_FILENAME]
    

(Note: Parameter names nonce and log must be verified against the source code).

6. Test Data Setup

  1. Install Plugin: Install Phrase TMS Integration for WordPress version 4.7.5.
  2. Create Subscriber: wp user create attacker attacker@example.com --role=subscriber --user_pass=password
  3. Generate Logs: Navigate to the plugin settings as Admin and trigger any action that generates a log (e.g., a test connection or manual sync) to ensure a file exists in the log directory.
  4. Confirm Log Path: Locate the log file on disk (usually under wp-content/uploads/memsource/).

7. Expected Results

  • Response: The server should return a 200 OK or a JSON success message (e.g., {"success":true}).
  • Effect: The targeted log file in the filesystem should be deleted.
  • Unauthorized Access: The operation succeeds even though the user is only a Subscriber.

8. Verification Steps

  1. Pre-check: ls -la wp-content/uploads/memsource/logs/ to confirm the log exists.
  2. Execute Exploit: Run the http_request tool with the Subscriber's cookies.
  3. Post-check: ls -la wp-content/uploads/memsource/logs/ to confirm the file is gone.
  4. Audit Logs: Check the PHP error log/WordPress debug log to see if any unlink() errors occurred (indicating the path was correct).

9. Alternative Approaches

  • Path Traversal: If the log parameter is not sanitized, check if it's possible to delete arbitrary files outside the log directory using ../.
  • Nonce Bypass: Check if the delete_log function uses check_ajax_referer with the $die parameter set to false and fails to check the return value.
  • Action Guessing: If delete_log is not the correct action name, grep for wp_ajax_ in the plugin directory to find all registered AJAX hooks.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Phrase TMS Integration for WordPress plugin fails to perform a capability check on its 'delete_log' AJAX endpoint. This allows any authenticated user, including those with Subscriber-level privileges, to delete log files by providing a valid nonce and the filename to be removed.

Vulnerable Code

// Likely located in a class handling admin AJAX actions, e.g., src/MemsourceConnector/Admin/Admin.php

add_action('wp_ajax_delete_log', array($this, 'delete_log'));

public function delete_log() {
    // Nonce check is present, but authorization check (e.g., current_user_can) is missing
    check_ajax_referer('memsource_nonce', 'nonce');

    $log_file = $_POST['log'];
    $log_dir = WP_CONTENT_DIR . '/uploads/memsource/logs/';
    $file_path = $log_dir . $log_file;

    if (file_exists($file_path)) {
        unlink($file_path);
    }
    
    wp_send_json_success();
}

Security Fix

--- a/src/MemsourceConnector/Admin/Admin.php
+++ b/src/MemsourceConnector/Admin/Admin.php
@@ -100,6 +100,10 @@
 public function delete_log() {
     check_ajax_referer('memsource_nonce', 'nonce');
 
+    if (!current_user_can('manage_options')) {
+        wp_die(__('You do not have sufficient permissions to access this page.', 'memsource-connector'));
+    }
+
     $log_file = sanitize_text_field($_POST['log']);
     $log_dir = WP_CONTENT_DIR . '/uploads/memsource/logs/';
     $file_path = $log_dir . $log_file;

Exploit Outline

The exploit targets the WordPress AJAX endpoint to perform unauthorized file deletion. 1. Authentication: The attacker must log in as any authenticated user (e.g., a Subscriber). 2. Nonce Acquisition: The attacker retrieves the 'memsource_nonce' value, which is often localized in the WordPress admin dashboard for plugin scripts using wp_localize_script. 3. Endpoint Target: A POST request is sent to /wp-admin/admin-ajax.php. 4. Payload: The request body contains 'action=delete_log', the 'nonce' parameter, and the 'log' parameter identifying the file to be deleted. 5. Outcome: Because the server only verifies the nonce and not the user's capabilities, the file residing in the plugin's log directory is deleted using the unlink() function.

Check if your site is affected.

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