CVE-2026-42657

Contest Gallery – Upload & Vote Photos, Media, Sell with PayPal & Stripe <= 28.1.7 - Missing Authorization

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
29.0.0
Patched in
6d
Time to patch

Description

The Contest Gallery – Upload & Vote Photos, Media, Sell with PayPal & Stripe plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 28.1.7. This makes it possible for unauthenticated attackers to perform an unauthorized action.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=28.1.7
PublishedApril 29, 2026
Last updatedMay 4, 2026
Affected plugincontest-gallery

What Changed in the Fix

Changes introduced in v29.0.0

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-42657 ## Vulnerability Summary The **Contest Gallery** plugin for WordPress is vulnerable to **Missing Authorization** in its AJAX handlers. Specifically, the function `post_cg_set_frontend_cookie` in `ajax/ajax-functions-frontend.php` is registered for unaut…

Show full research plan

Exploitation Research Plan - CVE-2026-42657

Vulnerability Summary

The Contest Gallery plugin for WordPress is vulnerable to Missing Authorization in its AJAX handlers. Specifically, the function post_cg_set_frontend_cookie in ajax/ajax-functions-frontend.php is registered for unauthenticated users via wp_ajax_nopriv_post_cg_set_frontend_cookie but lacks any nonce verification or capability checks. This allows an unauthenticated attacker to set sensitive session cookies (cg_order, contest-gal1ery-{ID}-voting, contest-gal1ery-{ID}-upload) that are used by the plugin to authorize access to orders, voting capabilities, and upload permissions.

Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Action: post_cg_set_frontend_cookie
  • Authentication: Unauthenticated (via wp_ajax_nopriv_)
  • Parameters:
    • gid: The Gallery ID (numeric).
    • cgIsUpload: (Optional) If set, triggers the creation of the upload authorization cookie.
    • cgOrderIdHash: (Optional) If set, triggers the creation of the cg_order cookie (used for order access).
  • Preconditions: The attacker needs to know a valid Gallery ID (easily found by viewing the site) or an Order ID hash.

Code Flow

1

Research Findings
Static analysis — not yet PoC-verified

Summary

The Contest Gallery plugin for WordPress fails to implement authorization checks or nonce verification on the `post_cg_set_frontend_cookie` AJAX function. This allows unauthenticated attackers to programmatically set session cookies that grant unauthorized access to restricted features such as photo uploading, voting, and private order details.

Vulnerable Code

// ajax/ajax-functions-frontend.php line 105
add_action('wp_ajax_nopriv_post_cg_set_frontend_cookie', 'post_cg_set_frontend_cookie');
add_action('wp_ajax_post_cg_set_frontend_cookie', 'post_cg_set_frontend_cookie');
if (!function_exists('post_cg_set_frontend_cookie')) {

    function post_cg_set_frontend_cookie()
    {

        global $wpdb;

        if (defined('DOING_AJAX') && DOING_AJAX) {

			if(!empty($_REQUEST['gid'])){
            $galeryID = intval(sanitize_text_field($_REQUEST['gid']));// is gidReal
			}

	        if(!empty($_POST['cgIsUpload'])){
		        if(!isset($_COOKIE['contest-gal1ery-'.$galeryID.'-upload'])) {
			        cg_set_cookie($galeryID,'upload');
			        // thats it cookie is set... after that cookie is available in browser
		        }
	        }elseif(!empty($_POST['cgOrderIdHash'])){
		        setcookie('cg_order',  cg_hash_function('---cg_order---'.sanitize_text_field($_POST['cgOrderIdHash'])), time() + ( 7 * 24 * 60 * 60), "/");
	        }else{
            if(!isset($_COOKIE['contest-gal1ery-'.$galeryID.'-voting'])) {
                cg_set_cookie($galeryID,'voting');
                // thats it cookie is set... after that cookie is available in browser
            }
	        }

            exit();
        } else {
            exit();
        }
    }
}

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/contest-gallery/28.1.7/ajax/ajax-functions-backend.php /home/deploy/wp-safety.org/data/plugin-versions/contest-gallery/29.0.0/ajax/ajax-functions-backend.php
--- /home/deploy/wp-safety.org/data/plugin-versions/contest-gallery/28.1.7/ajax/ajax-functions-backend.php	2026-04-06 19:43:48.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/contest-gallery/29.0.0/ajax/ajax-functions-backend.php	2026-04-19 21:25:02.000000000 +0000
@@ -1,10 +1,60 @@
 <?php
+if (!function_exists('cg_backend_ajax_error_json')) {
+    function cg_backend_ajax_error_json($message, $status = 400, $code = 'cg_backend_ajax_error') {
+        wp_send_json_error(array(
+            'message' => $message,
+            'code' => $code
+        ), $status);
+    }
+}
+
+if (!function_exists('cg_backend_ajax_require_access_json')) {
+    function cg_backend_ajax_require_access_json() {
+        if (!defined('DOING_AJAX') || !DOING_AJAX) {
+            cg_backend_ajax_error_json('Invalid AJAX request.', 400, 'cg_invalid_ajax_request');
+        }
+
+        if (!is_user_logged_in() || !cg_user_has_backend_access()) {
+            cg_backend_ajax_error_json('This area can be edited only as administrator, editor or author.', 403, 'cg_missing_rights');
+        }
+
+        $cg_nonce = '';
+        if (isset($_POST['cg_nonce'])) {
+            $cg_nonce = sanitize_text_field($_POST['cg_nonce']);
+        } elseif (isset($_GET['cg_nonce'])) {
+            $cg_nonce = sanitize_text_field($_GET['cg_nonce']);
+        }
+
+        if (empty($cg_nonce) || !wp_verify_nonce($cg_nonce, 'cg_nonce')) {
+            wp_send_json_error(array(
+                'message' => 'WP nonce security token not set or not valid anymore.',
+                'code' => 'cg_nonce_invalid',
+                'version' => cg_get_version()
+            ), 403);
+        }
+    }
+}
+
+if (!function_exists('cg_backend_ajax_validate_gallery_hash_json')) {
+    function cg_backend_ajax_validate_gallery_hash_json($GalleryID, $galleryHash) {
+        $GalleryID = absint($GalleryID);
+        if (empty($GalleryID) || empty($galleryHash)) {
+            cg_backend_ajax_error_json('Missing gallery validation data.', 403, 'cg_missing_gallery_hash');
+        }
+
+        $galleryHashToCompare = md5(wp_salt('auth') . '---cngl1---' . $GalleryID);
+        if ($galleryHash !== $galleryHashToCompare) {
+            cg_backend_ajax_error_json('Invalid gallery validation data.', 403, 'cg_invalid_gallery_hash');
+        }
+    }
+}
+
 // post_cg_get_current_permalinks
 add_action('wp_ajax_post_cg_get_current_permalinks', 'post_cg_get_current_permalinks');
 if (!function_exists('post_cg_get_current_permalinks')) {
     function post_cg_get_current_permalinks() {
 
-        cg_check_nonce();
+        cg_require_backend_access();
 
         global $wpdb;
         $tablename = $wpdb->prefix . "contest_gal1ery";

Exploit Outline

The exploit targets the `/wp-admin/admin-ajax.php` endpoint using the `post_cg_set_frontend_cookie` action. An unauthenticated attacker sends a POST request with the `gid` parameter set to a target Gallery ID. To gain upload permissions, they include the `cgIsUpload` parameter. To gain access to a specific order, they include the `cgOrderIdHash` parameter. The server responds by setting the corresponding session cookies (`contest-gal1ery-{ID}-upload` or `cg_order`) in the attacker's browser without verifying if the attacker is authorized to perform these actions or providing a valid nonce.

Check if your site is affected.

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