CVE-2026-32330

Photo Gallery by 10Web <= 1.8.37 - Cross-Site Request Forgery

mediumCross-Site Request Forgery (CSRF)
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
1.8.38
Patched in
67d
Time to patch

Description

The Photo Gallery by 10Web plugin for WordPress is vulnerable to Cross-Site Request Forgery in versions up to, and including, 1.8.37. This is due to missing or incorrect nonce validation on a function. This makes it possible for unauthenticated attackers to perform an unauthorized action via a forged request granted they can trick a site administrator into performing an action such as clicking on a link.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.8.37
PublishedFebruary 8, 2026
Last updatedApril 15, 2026
Affected pluginphoto-gallery

What Changed in the Fix

Changes introduced in v1.8.38

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-32330 ## 1. Vulnerability Summary The **Photo Gallery by 10Web** plugin (<= 1.8.37) is vulnerable to Cross-Site Request Forgery (CSRF). The vulnerability exists in the plugin's deactivation feedback mechanism located in `wd/includes/deactivate.php`. Specifica…

Show full research plan

Exploitation Research Plan - CVE-2026-32330

1. Vulnerability Summary

The Photo Gallery by 10Web plugin (<= 1.8.37) is vulnerable to Cross-Site Request Forgery (CSRF). The vulnerability exists in the plugin's deactivation feedback mechanism located in wd/includes/deactivate.php. Specifically, the function submit_and_deactivate, which is hooked to admin_init, fails to perform any nonce validation before processing a deactivation request.

By tricking an administrator into submitting a forged POST request, an attacker can force the plugin to generate a valid WordPress core deactivation nonce and redirect the administrator's browser to the plugin deactivation URL. This results in the unauthorized deactivation of the plugin.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/ (Any admin page, including admin-ajax.php, as it triggers admin_init)
  • Hook: admin_init
  • Vulnerable Function: TenWebNewLibDeactivate::submit_and_deactivate
  • Action: Deactivating the plugin.
  • Authentication Level: Unauthenticated to initiate the CSRF, but requires an Administrator to process the forged request.
  • Payload Parameter: bwg_submit_and_deactivate (where bwg is the plugin prefix).

3. Code Flow

  1. Entry Point: An administrator visits a malicious page while logged into WordPress.
  2. Forged Request: The malicious page sends a POST request to the WordPress site.
  3. Hook Trigger: WordPress processes the request; since it is directed at the admin area, it fires the admin_init hook.
  4. Vulnerable Callback: The admin_init hook triggers TenWebNewLibDeactivate::submit_and_deactivate() in wd/includes/deactivate.php.
  5. Parameter Check: The function checks if isset($_POST["bwg_submit_and_deactivate"]) (line 78).
  6. Logic Flaw: If the parameter equals 1 or 2, the code proceeds to generate a $deactivate_url using wp_create_nonce('deactivate-plugin_' . ...) (lines 100-104).
  7. Execution: The function echoes a <script> tag that sets window.location.href to this freshly generated, valid deactivation URL (line 105).
  8. Outcome: The administrator's browser follows the redirect, and because the nonce is valid and specific to the administrator's session, WordPress deactivates the plugin.

4. Nonce Acquisition Strategy

No nonce is required to initiate the attack.

This is a "Nonce Leakage/Generation" CSRF. The vulnerability is that the plugin generates the required WordPress core nonce for the attacker when the unprotected submit_and_deactivate function is called. The attacker does not need to know the nonce beforehand; they only need to trigger the code that creates it.

5. Exploitation Strategy

The exploitation will involve simulating an administrator submitting the forged request.

Step-by-Step Plan:

  1. Authenticate: Log in to the WordPress instance as an administrator using the login_as_admin tool.
  2. Trigger Vulnerability: Use the http_request tool to send a POST request to /wp-admin/ with the payload parameter.
  3. Payload:
    • Method: POST
    • URL: http://localhost:8080/wp-admin/admin-ajax.php (or any admin path)
    • Headers: Content-Type: application/x-www-form-urlencoded
    • Body: bwg_submit_and_deactivate=1
  4. Observe Response: The response should contain a script block similar to:
    <script>window.location.href=".../wp-admin/plugins.php?action=deactivate&plugin=photo-gallery%2Fphoto-gallery.php&_wpnonce=[NONCE_VALUE]";</script>
  5. Verify Inactivity: Check the plugin status via WP-CLI to confirm it has been deactivated.

6. Test Data Setup

  1. Install Plugin: Ensure "Photo Gallery by 10Web" version 1.8.37 is installed.
  2. Activate Plugin: Ensure the plugin is active: wp plugin activate photo-gallery.
  3. Confirm Status: Verify it is active before the exploit: wp plugin is-active photo-gallery.

7. Expected Results

  • The POST request to /wp-admin/admin-ajax.php returns a 200 OK status.
  • The response body contains the JavaScript redirect: window.location.href.
  • The redirect URL contains a valid _wpnonce for the deactivate-plugin_photo-gallery/photo-gallery.php action.
  • Following the redirect (or simply checking plugin status if using a real browser context) results in the plugin status changing to inactive.

8. Verification Steps

After performing the http_request, run the following WP-CLI command:

wp plugin is-active photo-gallery
  • Success Criteria: The command returns a non-zero exit code or explicitly states the plugin is inactive.
  • Secondary Verification: Check if the plugin exists but is deactivated:
wp plugin list --name=photo-gallery --field=status

Expected output: inactive.

9. Alternative Approaches

If a simple POST does not deactivate the plugin (e.g., if the agent doesn't execute the returned script), use browser_navigate to simulate the CSRF:

  1. Create a local HTML file on the agent's filesystem containing an auto-submitting form.
  2. Navigate the browser to that local file while the admin session is active.
  3. The browser will submit the form to /wp-admin/, execute the returned script, and follow the redirect to plugins.php, completing the deactivation.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Photo Gallery by 10Web plugin for WordPress is vulnerable to Cross-Site Request Forgery (CSRF) in versions up to 1.8.37 because the deactivation feedback handler fails to perform nonce validation. An attacker can trick an administrator into submitting a crafted POST request that forces the plugin to generate a valid WordPress core deactivation nonce and redirect the browser to the deactivation URL, leading to unauthorized plugin deactivation.

Vulnerable Code

// wd/includes/deactivate.php lines 74-107

  public function submit_and_deactivate() {
    $wd_options = $this->config;
    if ( isset($_POST[$wd_options->prefix . "_submit_and_deactivate"]) ) {

      if ( $_POST[$wd_options->prefix . "_submit_and_deactivate"] == 2 || $_POST[$wd_options->prefix . "_submit_and_deactivate"] == 3 ) {
        // ... logic for sending feedback to developer ...
      }
      if ( $_POST[$wd_options->prefix . "_submit_and_deactivate"] == 2 || $_POST[$wd_options->prefix . "_submit_and_deactivate"] == 1 ) {
        $deactivate_url = add_query_arg(array(
                                          'action' => 'deactivate',
                                          'plugin' => plugin_basename($wd_options->plugin_main_file),
                                          '_wpnonce' => wp_create_nonce('deactivate-plugin_' . plugin_basename($wd_options->plugin_main_file)),
                                        ), admin_url('plugins.php'));
        echo '<script>window.location.href="' . $deactivate_url . '";</script>';
      }
    }
  }

Security Fix

--- /home/deploy/wp-safety.org/data/plugin-versions/photo-gallery/1.8.37/wd/includes/deactivate.php\t2022-06-16 06:23:42.000000000 +0000\n+++ /home/deploy/wp-safety.org/data/plugin-versions/photo-gallery/1.8.38/wd/includes/deactivate.php\t2026-02-11 13:57:30.000000000 +0000\n@@ -73,7 +73,7 @@\n \n   public function submit_and_deactivate() {\n     $wd_options = $this->config;\n-    if ( isset($_POST[$wd_options->prefix . "_submit_and_deactivate"]) ) {\n+    if ( isset($_POST[$wd_options->prefix . "_submit_and_deactivate"]) && wp_verify_nonce($_POST[$wd_options->prefix . '_save_form_fild'], $wd_options->prefix . '_save_form') ) {\n \n       if ( $_POST[$wd_options->prefix . "_submit_and_deactivate"] == 2 || $_POST[$wd_options->prefix . "_submit_and_deactivate"] == 3 ) {\n         $data = array();

Exploit Outline

The exploit is a 'Nonce Leakage' CSRF that requires tricking an administrator into making a forged request. 1. The attacker creates a malicious page with a form that sends a POST request to /wp-admin/admin-ajax.php (which triggers admin_init). 2. The POST request includes the parameter 'bwg_submit_and_deactivate' set to '1'. 3. When the administrator visits this page, the form is submitted. 4. Because the plugin lacks nonce checks on the 'submit_and_deactivate' function, it generates a valid WordPress deactivation URL containing a fresh, session-specific '_wpnonce'. 5. The plugin then returns a <script> tag that automatically redirects the administrator's browser to this generated URL, resulting in the plugin being deactivated without the administrator's intent.

Check if your site is affected.

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