CVE-2026-25035

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

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
28.1.3
Patched in
11d
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.2.2. 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.2.2
PublishedMarch 23, 2026
Last updatedApril 2, 2026
Affected plugincontest-gallery

What Changed in the Fix

Changes introduced in v28.1.3

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Vulnerability Analysis: Missing Authorization in Contest Gallery (CVE-2026-25035) ## 1. Vulnerability Summary The **Contest Gallery** plugin (up to and including version 28.1.2.2) suffers from a **Missing Authorization** vulnerability. Specifically, several AJAX handlers registered for unauthenti…

Show full research plan

Vulnerability Analysis: Missing Authorization in Contest Gallery (CVE-2026-25035)

1. Vulnerability Summary

The Contest Gallery plugin (up to and including version 28.1.2.2) suffers from a Missing Authorization vulnerability. Specifically, several AJAX handlers registered for unauthenticated users (wp_ajax_nopriv_) lack proper capability checks or effective nonce protection.

The most critical flaw is the presence of an "Authorization Oracle" endpoint (post_cg1l_current_frontend_nonce) that explicitly provides valid nonces to unauthenticated users, combined with other unauthenticated endpoints like post_cg_set_frontend_cookie that allow manipulation of sensitive session/order data without any verification. This enables unauthenticated attackers to perform unauthorized actions such as spoofing order identifiers or casting votes in restricted contests.

2. Attack Vector Analysis

  • Endpoints: wp-admin/admin-ajax.php
  • Actions:
    • post_cg1l_current_frontend_nonce (To obtain nonces)
    • post_cg_set_frontend_cookie (To spoof order hashes/voting status)
    • post_cg_rate_v10_oneStar / post_cg_rate_v10_fiveStar (To bypass voting restrictions)
  • Parameters: action, gid, cgOrderIdHash, cgIsUpload, nonce.
  • Authentication:
Research Findings
Static analysis — not yet PoC-verified

Summary

The plugin exposes an 'Authorization Oracle' via the `post_cg1l_current_frontend_nonce` AJAX endpoint, which provides valid security nonces to unauthenticated users. This allows attackers to bypass nonce protections on other sensitive endpoints to perform unauthorized actions such as casting multiple votes or spoofing order identifiers.

Vulnerable Code

// ajax/ajax-functions-frontend.php L181-197
add_action('wp_ajax_nopriv_post_cg1l_current_frontend_nonce', 'post_cg1l_current_frontend_nonce');
add_action('wp_ajax_post_cg1l_current_frontend_nonce', 'post_cg1l_current_frontend_nonce');
if (!function_exists('post_cg1l_current_frontend_nonce')) {

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

        ?>
        <script data-cg-processing-current-nonce="true">
            cgJsClass.gallery.vars.currentCgNonce = <?php echo json_encode(wp_create_nonce('cg1l_action')); ?>;
        </script>
        <?php
            exit();
        } else {
            exit();
        }
    }
}

---

// ajax/ajax-functions-frontend.php L104-124
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']));
            }
            if(!empty($_POST['cgIsUpload'])){
                // ...
            }elseif(!empty($_POST['cgOrderIdHash'])){
                setcookie('cg_order',  cg_hash_function('---cg_order---'.sanitize_text_field($_POST['cgOrderIdHash'])), time() + ( 7 * 24 * 60 * 60), "/");
            }else{
                // ...
            }
            exit();
        } else {
            exit();
        }
    }
}

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/contest-gallery/28.1.2.2/ajax/ajax-functions-frontend.php /home/deploy/wp-safety.org/data/plugin-versions/contest-gallery/28.1.3/ajax/ajax-functions-frontend.php
--- /home/deploy/wp-safety.org/data/plugin-versions/contest-gallery/28.1.2.2/ajax/ajax-functions-frontend.php	2026-01-12 16:50:46.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/contest-gallery/28.1.3/ajax/ajax-functions-frontend.php	2026-01-17 15:00:28.000000000 +0000
@@ -183,12 +183,17 @@
     function post_cg1l_current_frontend_nonce()
     {
         if (defined('DOING_AJAX') && DOING_AJAX) {
-
+			$WpUserId = absint($_POST['cgJustLoggedInWpUserId']);
+			$cgGetLoggedInFrontendUserKey = sanitize_text_field($_POST['cgGetLoggedInFrontendUserKey']);
+			$cgGetLoggedInFrontendUserKeyToCompare = get_user_meta( $WpUserId,'cgGetLoggedInFrontendUserKey',true);
+			if(!empty($cgGetLoggedInFrontendUserKeyToCompare) && $cgGetLoggedInFrontendUserKeyToCompare == $cgGetLoggedInFrontendUserKey){
         ?>
         <script data-cg-processing-current-nonce="true">
             cgJsClass.gallery.vars.currentCgNonce = <?php echo json_encode(wp_create_nonce('cg1l_action')); ?>;
         </script>
         <?php
+				delete_user_meta( $WpUserId,'cgGetLoggedInFrontendUserKey');
+			}
             exit();
         } else {
             exit();
@@ -206,6 +211,9 @@
             $tablename = $wpdb->prefix . "contest_gal1ery";
             $gid = absint($_POST['cgl_gid']);
             $activation_key = sanitize_text_field($_POST['cglKey']);
+			if(empty($activation_key)){
+				exit();
+			}
             $userRow = $wpdb->get_row(
                 $wpdb->prepare(
                     "SELECT *

Exploit Outline

An unauthenticated attacker can exploit this vulnerability by first sending a request to `wp-admin/admin-ajax.php` with the action `post_cg1l_current_frontend_nonce`. The server responds with a valid nonce for the `cg1l_action` action. With this nonce, the attacker can then invoke other unauthenticated AJAX actions that rely on `cg_check_frontend_nonce()`, such as `post_cg_rate_v10_oneStar` or `post_cg_rate_v10_fiveStar`, to manipulate voting results. Additionally, an attacker can use the `post_cg_set_frontend_cookie` action to manipulate session cookies (like `cg_order`) by providing arbitrary `cgOrderIdHash` values, potentially spoofing orders or bypassing frontend restrictions.

Check if your site is affected.

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