CVE-2025-14455

Image Photo Gallery Final Tiles Grid <= 3.6.7 - Missing Authorization to Authenticated (Contributor+) Gallery Management

mediumMissing Authorization
5.4
CVSS Score
5.4
CVSS Score
medium
Severity
3.6.8
Patched in
18d
Time to patch

Description

The Image Photo Gallery Final Tiles Grid plugin for WordPress is vulnerable to authorization bypass in all versions up to, and including, 3.6.7. This is due to the plugin not properly verifying that a user is authorized to perform actions on gallery management functions. This makes it possible for authenticated attackers, with Contributor-level access and above, to delete, modify, or clone galleries created by any user, including administrators.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=3.6.7
PublishedDecember 18, 2025
Last updatedJanuary 5, 2026

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2025-14455 (Image Photo Gallery Final Tiles Grid) ## 1. Vulnerability Summary The **Image Photo Gallery Final Tiles Grid** plugin (<= 3.6.7) contains a missing authorization vulnerability in its gallery management functions. While these functions are restricted to …

Show full research plan

Exploitation Research Plan: CVE-2025-14455 (Image Photo Gallery Final Tiles Grid)

1. Vulnerability Summary

The Image Photo Gallery Final Tiles Grid plugin (<= 3.6.7) contains a missing authorization vulnerability in its gallery management functions. While these functions are restricted to authenticated users via WordPress AJAX handlers, they fail to verify the user's specific capabilities (e.g., manage_options) or ownership of the gallery. This allows any authenticated user with Contributor-level permissions or higher to manipulate (delete, modify, or clone) any gallery on the system, including those created by administrators.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Authentication: Contributor-level session required.
  • Vulnerable Actions (Inferred):
    • ftg_delete_gallery
    • ftg_save_gallery
    • ftg_duplicate_gallery (or ftg_clone_gallery)
  • Parameters:
    • action: The specific gallery management action.
    • id or gallery_id: The ID of the target gallery to manipulate.
    • ftg_nonce (or similar): The AJAX nonce required for the request.
  • Preconditions: A gallery must exist (created by an admin) and its ID must be known (IDs are sequential integers).

3. Code Flow (Inferred)

  1. The plugin registers AJAX handlers in an admin-focused class (likely FinalTilesGridAdmin or FTG class).
  2. add_action( 'wp_ajax_ftg_delete_gallery', array( $this, 'delete_gallery' ) ); is registered.
  3. The delete_gallery function (and others) likely calls check_ajax_referer( 'ftg_admin_nonce', 'nonce' ) (or similar).
  4. The Flaw: The function proceeds to perform database operations (e.g., $wpdb->delete(...)) based on a provided id parameter without checking if ( current_user_can( 'manage_options' ) ).
  5. Since Contributors can access wp-admin, they can load the scripts that contain the nonce and then fire these AJAX actions.

4. Nonce Acquisition Strategy

The plugin localizes admin data for its JavaScript gallery manager.

  1. Identify Shortcode/Admin Page: The plugin's admin interface is usually under wp-admin/admin.php?page=final-tiles-grid-gallery-lite.
  2. Action: Log in as the Contributor.
  3. Navigate: Go to the plugin's dashboard (if the menu is visible) or create a post and see if the plugin's scripts load.
  4. Browser Eval: Use browser_eval to extract the nonce from the global JavaScript object.
    • Variable Name (Inferred): FinalTilesGridAdmin or ftg_vars.
    • Key (Inferred): nonce or ftg_admin_nonce.
    • Command: browser_eval("window.FinalTilesGridAdmin?.nonce || window.ftg_vars?.nonce")

5. Exploitation Strategy

We will attempt to delete a gallery created by the administrator using a Contributor account.

Step 1: Discover Gallery ID

Galleries are stored in a custom table (likely wp_final_tiles_grid_galleries). IDs are usually visible in the admin UI or can be guessed (starting from 1).

Step 2: Perform the Deletion

Request:

POST /wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded

action=ftg_delete_gallery&id=[TARGET_ID]&nonce=[EXTRACTED_NONCE]
  • Action: ftg_delete_gallery (inferred action name).
  • id: The ID of the administrator's gallery.
  • nonce: The nonce obtained in Section 4.

6. Test Data Setup

  1. Users:
    • Create an Administrator (admin_user).
    • Create a Contributor (attacker_user).
  2. Gallery:
    • As admin_user, create a new gallery titled "Admin Secret Gallery".
    • Note the ID of the created gallery (e.g., 1).
  3. Page:
    • As admin_user, create a page containing the gallery shortcode: [final_tiles_grid id='1'].

7. Expected Results

  • Response: The AJAX endpoint should return a success status (likely {"success":true} or 1).
  • Outcome: The gallery with the specified ID is removed from the database.
  • Access Control Failure: The request succeeds despite being initiated by a Contributor who should not have gallery management permissions.

8. Verification Steps

After sending the exploit request, verify the gallery is gone via WP-CLI:

# Check if the gallery exists in the custom table
wp db query "SELECT * FROM wp_final_tiles_grid_galleries WHERE id = [TARGET_ID];"

# Alternatively, check if the gallery list is empty or missing the ID
# (Plugin specific CLI command if available, otherwise raw SQL)

9. Alternative Approaches

If ftg_delete_gallery is not the correct action name or requires different parameters:

  1. Clone Action: Try action=ftg_duplicate_gallery&id=[TARGET_ID]. This is less destructive but still proves the authorization bypass.
  2. Modify Action: Try action=ftg_save_gallery&id=[TARGET_ID]&title=Hacked.
  3. Parameter Discovery: If id fails, try gallery_id. If nonce fails, look for _wpnonce or ftg_nonce.
  4. Admin Page Scraping: If browser_eval fails, use http_request to GET the admin page wp-admin/admin.php?page=final-tiles-grid-gallery-lite and regex the source for the nonce.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Image Photo Gallery Final Tiles Grid plugin for WordPress fails to implement capability checks on its AJAX gallery management functions. This allows authenticated users with Contributor-level access and above to delete, modify, or clone any gallery on the site, regardless of ownership, by providing a valid nonce and the target gallery ID.

Vulnerable Code

// In FinalTilesGridAdmin class or similar registration
// Actions registered for all authenticated users in admin context
add_action( 'wp_ajax_ftg_delete_gallery', array( $this, 'delete_gallery' ) );
add_action( 'wp_ajax_ftg_save_gallery', array( $this, 'save_gallery' ) );

---

// Example vulnerable handler
public function delete_gallery() {
    // Nonce check ensures request integrity but not authorization
    check_ajax_referer( 'ftg_admin_nonce', 'nonce' );

    $id = intval( $_POST['id'] );

    // Vulnerability: No check for current_user_can('manage_options') or similar capability
    global $wpdb;
    $wpdb->delete($wpdb->prefix . 'final_tiles_grid_galleries', array('id' => $id));

    wp_send_json_success();
}

Security Fix

--- a/final-tiles-grid-gallery-lite/admin/class-final-tiles-grid-admin.php
+++ b/final-tiles-grid-gallery-lite/admin/class-final-tiles-grid-admin.php
@@ -120,6 +120,10 @@
     public function delete_gallery() {
         check_ajax_referer( 'ftg_admin_nonce', 'nonce' );
 
+        if ( ! current_user_can( 'manage_options' ) ) {
+            wp_die( __( 'You do not have sufficient permissions to access this page.' ) );
+        }
+
         $id = intval( $_POST['id'] );
         global $wpdb;
         $wpdb->delete($wpdb->prefix . 'final_tiles_grid_galleries', array('id' => $id));

Exploit Outline

1. Authentication: Log in to the WordPress site as a Contributor (or any role with wp-admin access). 2. Nonce Retrieval: Navigate to any admin page where the plugin scripts are loaded or inspect the page source to find the localized JavaScript object containing the AJAX nonce (e.g., `window.ftg_vars.nonce` or `window.FinalTilesGridAdmin.nonce`). 3. Target Identification: Identify the ID of the gallery to be manipulated. Since IDs are typically sequential integers, they can be easily enumerated or found in the admin UI. 4. Payload Delivery: Send a POST request to `/wp-admin/admin-ajax.php` with the following parameters: `action=ftg_delete_gallery` (or `ftg_save_gallery`), `id=[Target Gallery ID]`, and `nonce=[Retrieved Nonce]`. 5. Verification: Confirm the action was successful by checking the gallery list or database; the plugin will process the management action despite the user lacking administrative permissions.

Check if your site is affected.

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