[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fIkJFL90PkdadTB9xEE3T-KE-XpQvJXiTuMP5iD58mtU":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":25,"research_verified":26,"research_rounds_completed":27,"research_plan":28,"research_summary":29,"research_vulnerable_code":30,"research_fix_diff":31,"research_exploit_outline":32,"research_model_used":33,"research_started_at":34,"research_completed_at":35,"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":26,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":26,"source_links":36},"CVE-2026-54190","envira-gallery-image-photo-gallery-albums-video-gallery-slideshows-more-missing-authorization","Envira Gallery – Image Photo Gallery, Albums, Video Gallery, Slideshows & More \u003C= 1.12.5 - Missing Authorization","The Envira Gallery – Image Photo Gallery, Albums, Video Gallery, Slideshows & More plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 1.12.5. This makes it possible for unauthenticated attackers to perform an unauthorized action.","envira-gallery-lite",null,"\u003C=1.12.5","1.12.6","medium",5.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Missing Authorization","2026-06-15 00:00:00","2026-06-23 16:01:01",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F7289e651-a959-4cf1-8e45-538bae22029a?source=api-prod",9,[22,23,24],"envira-gallery-lite.php","includes\u002Fglobal\u002Fconvert_gallery\u002FConvert_Gallery_REST.php","readme.txt","researched",false,3,")\n    `envira_convert_process_items` (>)\n    \n    What if the `permission_callback` returns `true` if the user is unauthenticated?\n    No.\n    \n    Let's look at `OnboardingWizard` again.\n    Many Envira vulnerabilities are in the AJAX handlers.\n    But the description says \"Missing Authorization\".\n    \n    Let's try to find if `Convert_Gallery_REST` has a vulnerability.\n    What if unauthenticated users can call `envira_convert_process_items`?\n    It has a `permission_callback` called `verify_process_gallery_permission`.\n    If `$this->can_edit_post( $post_id )` returns `true` for unauthenticated users...\n    Why would it?\n    Maybe if `$post_id` is a post that is \"public\"?\n    In WordPress, `current_user_can('edit_post', $post_id)` returns false for unauthenticated users regardless of the post status.\n\n    *Aha!* I see something in the `envira-gallery-lite.php` file.\n    ```php\n\t\t\u002F\u002F Load global components.\n\t\t$this->require_global();\n\n\t\t\u002F\u002F Load admin only components.\n\t\tif ( is_admin() ) {\n\t\t\t$this->require_admin();\n\t\t}\n    ```\n    \n    Wait, look at the `require_global()` call. It loads `rest.php`.\n    Inside","The Envira Gallery plugin for WordPress is vulnerable to unauthorized access because its REST API permission callbacks return a WP_REST_Response object instead of a boolean or WP_Error upon failure. This causes the WordPress REST API to treat the result as truthy, allowing unauthenticated attackers to bypass authorization and trigger gallery conversion or processing actions.","\u002F\u002F includes\u002Fglobal\u002Fconvert_gallery\u002FConvert_Gallery_REST.php:83\npublic function verify_convert_gallery_permission( $request ) {\n\n    \u002F\u002F Get post ID from request - support both postId and post_id for backward compatibility.\n    $post_id = absint( $request->get_param( 'post_id' ) );\n    if ( $post_id \u003C= 0 ) {\n        $post_id = absint( $request->get_param( 'postId' ) );\n    }\n\n    if ( $post_id \u003C= 0 ) {\n        return new WP_REST_Response( [ 'message' => __( 'A valid post ID is required.', 'envira-gallery-lite' ) ], 400 );\n    }\n\n    \u002F\u002F Check if user can edit the post.\n    if ( ! $this->can_edit_post( $post_id ) ) {\n        return new WP_REST_Response( [ 'message' => __( 'You do not have permission to edit this post.', 'envira-gallery-lite' ) ], 403 );\n    }\n\n    return true;\n}\n\n---\n\n\u002F\u002F includes\u002Fglobal\u002Fconvert_gallery\u002FConvert_Gallery_REST.php:144\npublic function verify_process_gallery_permission( $request ) {\n\n    \u002F\u002F Get post ID from request - support both postId and post_id for backward compatibility.\n    $post_id = absint( $request->get_param( 'post_id' ) );\n    \u002F\u002F ... (truncated)\n    \u002F\u002F Check if user can edit the post.\n    if ( ! $this->can_edit_post( $post_id ) ) {\n        return new WP_REST_Response( [ 'error' => __( 'You do not have permission to edit this post.', 'envira-gallery-lite' ) ], 403 );\n    }\n\n    return true;\n}","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fenvira-gallery-lite\u002F1.12.5\u002Fincludes\u002Fglobal\u002Fconvert_gallery\u002FConvert_Gallery_REST.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fenvira-gallery-lite\u002F1.12.6\u002Fincludes\u002Fglobal\u002Fconvert_gallery\u002FConvert_Gallery_REST.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fenvira-gallery-lite\u002F1.12.5\u002Fincludes\u002Fglobal\u002Fconvert_gallery\u002FConvert_Gallery_REST.php\t2026-04-23 16:54:48.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fenvira-gallery-lite\u002F1.12.6\u002Fincludes\u002Fglobal\u002Fconvert_gallery\u002FConvert_Gallery_REST.php\t2026-05-27 14:58:50.000000000 +0000\n@@ -61,7 +61,7 @@\n \t * Verify REST request nonce.\n \t *\n \t * @param WP_REST_Request $request Request object.\n-\t * @return bool|WP_REST_Response\n+\t * @return bool|WP_Error\n \t *\u002F\n \tpublic function verify_rest_nonce( $request ) {\n \t\t\u002F\u002F Get the nonce from the request header.\n@@ -69,7 +69,7 @@\n \n \t\t\u002F\u002F Verify the nonce.\n \t\tif ( ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {\n-\t\t\treturn new WP_REST_Response( [ 'message' => __( 'Security check failed. You are not authorized. Please refresh and try again.', 'envira-gallery-lite' ) ], 403 );\n+\t\t\treturn new WP_Error( 'rest_forbidden', __( 'Security check failed. You are not authorized. Please refresh and try again.', 'envira-gallery-lite' ), [ 'status' => 403 ] );\n \t\t}\n \n \t\t\u002F\u002F Return true if valid.\n@@ -80,10 +80,14 @@\n \t * Permission callback for single gallery conversion.\n \t *\n \t * @param WP_REST_Request $request Request object.\n-\t * @return bool|WP_REST_Response\n+\t * @return bool|WP_Error\n \t *\u002F\n \tpublic function verify_convert_gallery_permission( $request ) {\n \n+\t\tif ( ! is_user_logged_in() ) {\n+\t\t\treturn new WP_Error( 'rest_not_logged_in', __( 'You must be logged in to perform this action.', 'envira-gallery-lite' ), [ 'status' => 401 ] );\n+\t\t}\n+\n \t\t\u002F\u002F Get post ID from request - support both postId and post_id for backward compatibility.\n \t\t$post_id = absint( $request->get_param( 'post_id' ) );\n \t\tif ( $post_id \u003C= 0 ) {\n@@ -91,12 +95,12 @@\n \t\t}\n \n \t\tif ( $post_id \u003C= 0 ) {\n-\t\t\treturn new WP_REST_Response( [ 'message' => __( 'A valid post ID is required.', 'envira-gallery-lite' ) ], 400 );\n+\t\t\treturn new WP_Error( 'rest_bad_request', __( 'A valid post ID is required.', 'envira-gallery-lite' ), [ 'status' => 400 ] );\n \t\t}\n \n \t\t\u002F\u002F Check if user can edit the post.\n \t\tif ( ! $this->can_edit_post( $post_id ) ) {\n-\t\t\treturn new WP_REST_Response( [ 'message' => __( 'You do not have permission to edit this post.', 'envira-gallery-lite' ) ], 403 );\n+\t\t\treturn new WP_Error( 'rest_forbidden', __( 'You do not have permission to edit this post.', 'envira-gallery-lite' ), [ 'status' => 403 ] );\n \t\t}\n \n \t\treturn true;\n@@ -106,32 +110,36 @@\n \t * Permission callback for bulk gallery conversion.\n \t *\n \t * @param WP_REST_Request $request Request object.\n-\t * @return bool|WP_REST_Response\n+\t * @return bool|WP_Error\n \t *\u002F\n \tpublic function verify_bulk_convert_permission( $request ) {\n \n+\t\tif ( ! is_user_logged_in() ) {\n+\t\t\treturn new WP_Error( 'rest_not_logged_in', __( 'You must be logged in to perform this action.', 'envira-gallery-lite' ), [ 'status' => 401 ] );\n+\t\t}\n+\n \t\t\u002F\u002F Check bulk conversion capability.\n \t\t$capability = apply_filters( 'envira_convert_bulk_galleries_cap', 'manage_options' );\n \t\tif ( ! current_user_can( $capability ) ) {\n-\t\t\treturn new WP_REST_Response( [ 'message' => __( 'You do not have permission to access this feature.', 'envira-gallery-lite' ) ], 403 );\n+\t\t\treturn new WP_Error( 'rest_forbidden', __( 'You do not have permission to access this feature.', 'envira-gallery-lite' ), [ 'status' => 403 ] );\n \t\t}\n \n \t\t\u002F\u002F Get post type from request.\n \t\t$selected_posttype = sanitize_text_field( $request->get_param( 'selected_posttype' ) );\n \n \t\tif ( empty( $selected_posttype ) ) {\n-\t\t\treturn new WP_REST_Response( [ 'message' => __( 'A post type is required for conversion. Please make a selection.', 'envira-gallery-lite' ) ], 400 );\n+\t\t\treturn new WP_Error( 'rest_bad_request', __( 'A post type is required for conversion. Please make a selection.', 'envira-gallery-lite' ), [ 'status' => 400 ] );\n \t\t}\n \n \t\tif ( ! post_type_exists( $selected_posttype ) ) {\n-\t\t\treturn new WP_REST_Response( [ 'message' => __( 'Post type not recognized. Please check your selection and try again.', 'envira-gallery-lite' ) ], 404 );\n+\t\t\treturn new WP_Error( 'rest_not_found', __( 'Post type not recognized. Please check your selection and try again.', 'envira-gallery-lite' ), [ 'status' => 404 ] );\n \t\t}\n \n \t\t\u002F\u002F Check if the current user can edit the selected post type.\n \t\t$post_type_object = get_post_type_object( $selected_posttype );\n \t\tif ( ! current_user_can( $post_type_object->cap->edit_posts ) ) {\n \t\t\t\u002F\u002F translators: %s is the post type singular name.\n-\t\t\treturn new WP_REST_Response( [ 'message' => sprintf( __( 'You do not have permission to edit %s item(s).', 'envira-gallery-lite' ), $post_type_object->labels->singular_name ) ], 403 );\n+\t\t\treturn new WP_Error( 'rest_forbidden', sprintf( __( 'You do not have permission to edit %s item(s).', 'envira-gallery-lite' ), $post_type_object->labels->singular_name ), [ 'status' => 403 ] );\n \t\t}\n \n \t\treturn true;\n@@ -141,10 +149,14 @@\n \t * Permission callback for processing gallery items.\n \t *\n \t * @param WP_REST_Request $request Request object.\n-\t * @return bool|WP_REST_Response\n+\t * @return bool|WP_Error\n \t *\u002F\n \tpublic function verify_process_gallery_permission( $request ) {\n \n+\t\tif ( ! is_user_logged_in() ) {\n+\t\t\treturn new WP_Error( 'rest_not_logged_in', __( 'You must be logged in to perform this action.', 'envira-gallery-lite' ), [ 'status' => 401 ] );\n+\t\t}\n+\n \t\t\u002F\u002F Get post ID from request - support both postId and post_id for backward compatibility.\n \t\t$post_id = absint( $request->get_param( 'post_id' ) );\n \t\tif ( $post_id \u003C= 0 ) {\n@@ -152,19 +164,19 @@\n \t\t}\n \n \t\tif ( $post_id \u003C= 0 ) {\n-\t\t\treturn new WP_REST_Response( [ 'error' => __( 'A valid post ID is required.', 'envira-gallery-lite' ) ], 400 );\n+\t\t\treturn new WP_Error( 'rest_bad_request', __( 'A valid post ID is required.', 'envira-gallery-lite' ), [ 'status' => 400 ] );\n \t\t}\n \n \t\t\u002F\u002F Get the post.\n \t\t$post = get_post( $post_id );\n \n \t\tif ( ! $post ) {\n-\t\t\treturn new WP_REST_Response( [ 'error' => __( 'Post not found.', 'envira-gallery-lite' ) ], 400 );\n+\t\t\treturn new WP_Error( 'rest_not_found', __( 'Post not found.', 'envira-gallery-lite' ), [ 'status' => 404 ] );\n \t\t}\n \n \t\t\u002F\u002F Check if user can edit the post.\n \t\tif ( ! $this->can_edit_post( $post_id ) ) {\n-\t\t\treturn new WP_REST_Response( [ 'error' => __( 'You do not have permission to edit this post.', 'envira-gallery-lite' ) ], 403 );\n+\t\t\treturn new WP_Error( 'rest_forbidden', __( 'You do not have permission to edit this post.', 'envira-gallery-lite' ), [ 'status' => 403 ] );\n \t\t}\n \n \t\treturn true;","The exploit involves sending an unauthenticated POST request to the `\u002Fwp-json\u002Fenvira-convert\u002Fv1\u002Fconvert-gallery` or `\u002Fwp-json\u002Fenvira-convert\u002Fv1\u002Fprocess-gallery` endpoints. Because the `permission_callback` returns a `WP_REST_Response` object when authorization fails (e.g., when `can_edit_post` is false), the WordPress REST API infrastructure incorrectly evaluates this object as `true`. This bypasses the intended capability check, allowing the unauthenticated request to reach the core callback logic, where an attacker can supply a `post_id` and image data to manipulate gallery content or trigger conversion processes.","gemini-3-flash-preview","2026-06-26 00:10:43","2026-06-26 00:12:24",{"type":37,"vulnerable_version":38,"fixed_version":11,"vulnerable_browse":39,"vulnerable_zip":40,"fixed_browse":41,"fixed_zip":42,"all_tags":43},"plugin","1.12.5","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fenvira-gallery-lite\u002Ftags\u002F1.12.5","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fenvira-gallery-lite.1.12.5.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fenvira-gallery-lite\u002Ftags\u002F1.12.6","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fenvira-gallery-lite.1.12.6.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fenvira-gallery-lite\u002Ftags"]