ACF Photo Gallery Field <= 3.0 - Missing Authorization to Authenticated (Subscriber+) Attachment Metadata Modification
Description
The ACF Photo Gallery Field plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the "acf_photo_gallery_edit_save" function in all versions up to, and including, 3.0. This makes it possible for authenticated attackers, with subscriber level access and above, to modify the title, caption, and custom metadata of arbitrary media attachments.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=3.0Source Code
WordPress.org SVNThis plan outlines the research and exploitation steps for CVE-2025-12081, a missing authorization vulnerability in the **ACF Photo Gallery Field** plugin. --- ### 1. Vulnerability Summary **ID:** CVE-2025-12081 **Plugin:** ACF Photo Gallery Field (`navz-photo-gallery`) **Affected Versions:** …
Show full research plan
This plan outlines the research and exploitation steps for CVE-2025-12081, a missing authorization vulnerability in the ACF Photo Gallery Field plugin.
1. Vulnerability Summary
ID: CVE-2025-12081
Plugin: ACF Photo Gallery Field (navz-photo-gallery)
Affected Versions: <= 3.0
Vulnerability Type: Missing Authorization
CVSS: 4.3 (Medium)
Vulnerable Function: acf_photo_gallery_edit_save
The vulnerability exists because the function acf_photo_gallery_edit_save, which is hooked to the wp_ajax_acf_photo_gallery_edit_save action, lacks a capability check (e.g., current_user_can()). While it may verify a nonce, that nonce is typically available to any authenticated user who can access an admin page or a page where the ACF gallery field is rendered. This allows a Subscriber-level user to modify the title, caption, and metadata of any WordPress media attachment by specifying its ID.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Method: POST
- Action:
acf_photo_gallery_edit_save - Authentication Required: Subscriber-level (authenticated)
- Vulnerable Parameters:
id: The ID of the target attachment to modify.title: The new title for the attachment.caption: The new caption.alt: The new Alt text.description: The new description.
- Preconditions: The attacker must be logged in as at least a Subscriber and have a valid AJAX nonce.
3. Code Flow (Inferred)
- Entry Point: WordPress receives a POST request to
admin-ajax.phpwithaction=acf_photo_gallery_edit_save. - Hook Execution: WordPress triggers the action
wp_ajax_acf_photo_gallery_edit_save. - Handler Function: The function
acf_photo_gallery_edit_save()is called. - Nonce Verification: The function likely calls
check_ajax_referer( 'acf_photo_gallery_nonce', 'nonce' )or similar. - Missing Auth Check: The function proceeds to update the attachment without checking if the current user has the
edit_postsoredit_others_postscapability. - Data Sink: The function uses
wp_update_post()for the title/caption andupdate_post_meta()for the alt text and description, targeting the user-suppliedid.
4. Nonce Acquisition Strategy
The plugin likely enqueues a script that localizes the nonce for the gallery editing modal.
- Identify Script Localization: The plugin likely uses
wp_localize_script()in its main file or an admin-related include.- Possible JS Object:
acf_photo_gallery_js_obj(inferred from plugin name) - Possible Nonce Key:
nonceoracf_photo_gallery_nonce
- Possible JS Object:
- Determine Page Source: The nonce is likely available on any page where the ACF field is active in the editor. However, if the plugin enqueues the script globally in the admin area, any Subscriber can find it on
/wp-admin/profile.php. - Extraction Steps:
- Log in as a Subscriber.
- Navigate to
/wp-admin/profile.php. - Use
browser_evalto search for the nonce:// Example search for the nonce object window.acf_photo_gallery_js_obj?.nonce || window.navz_gallery_obj?.nonce - If not found on the profile page, check if the nonce is exposed on the frontend where a gallery is displayed.
5. Test Data Setup
- Install Plugin: Install and activate
navz-photo-galleryversion 3.0. - Target Media: As an Administrator, upload an image to the Media Library. Note its ID (e.g.,
123).- Set initial values: Title="Original Title", Caption="Original Caption".
- Attacker User: Create a user with the Subscriber role.
- ACF Field (Optional): You may need to create an ACF Field Group with a "Photo Gallery" field and assign it to "Posts" to ensure the plugin's scripts load.
6. Exploitation Strategy
Once the Subscriber user is created and the target Attachment ID is known:
Step 1: Extract the Nonce
- Log in as the Subscriber.
- Navigate to the WordPress dashboard (
/wp-admin/). - Execute
browser_evalto find the nonce variable.- Note: Check the page source for
wp_localize_scriptoutput to find the exact variable name.
- Note: Check the page source for
Step 2: Execute the Modification
- Use
http_requestto send the payload.
Payload Request:
POST /wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
action=acf_photo_gallery_edit_save&nonce=[EXTRACTED_NONCE]&id=[TARGET_ATTACHMENT_ID]&title=Vulnerable+Title&caption=Vulnerable+Caption&alt=Vulnerable+Alt&description=Vulnerable+Desc
7. Expected Results
- Response: The server should return a successful status (usually
1or a JSON success message like{"success":true}). - Effect: The media attachment with the specified ID will have its title changed to "Vulnerable Title" and caption changed to "Vulnerable Caption", regardless of who owns the attachment.
8. Verification Steps
- WP-CLI Check:
wp post get [TARGET_ATTACHMENT_ID] --field=post_title wp post get [TARGET_ATTACHMENT_ID] --field=post_excerpt # This is the caption wp post_meta get [TARGET_ATTACHMENT_ID] _wp_attachment_image_alt - Success Criteria: The output of these commands should match the "Vulnerable" strings sent in the payload.
9. Alternative Approaches
- LFI/Unserialize Check: If the metadata modification allows updating arbitrary meta keys, check if
_wp_attached_filecan be modified (Path Traversal/LFI risk) or if other sensitive meta can be overwritten. - Frontend Check: If the Subscriber cannot access
/wp-admin/, check if the plugin exposes the nonce on the frontend for users who can view posts containing the gallery field. - Action Guessing: If the exact nonce action name is unknown, search the plugin source code for
wp_create_nonceorcheck_ajax_referer. (e.g.,grep -r "check_ajax_referer" .)
Summary
The ACF Photo Gallery Field plugin for WordPress lacks authorization checks in its AJAX handler for saving attachment metadata. Authenticated users with Subscriber-level permissions or higher can modify the title, caption, description, and alternative text of any media attachment by providing a valid nonce and the target attachment ID.
Vulnerable Code
// Likely located in the main plugin file or an admin handler add_action( 'wp_ajax_acf_photo_gallery_edit_save', 'acf_photo_gallery_edit_save' ); function acf_photo_gallery_edit_save() { // Nonce check exists, but any authenticated user can typically access this nonce check_ajax_referer( 'acf_photo_gallery_nonce', 'nonce' ); // Missing capability check (e.g., current_user_can( 'edit_posts' )) $id = intval( $_POST['id'] ); $post = array( 'ID' => $id, 'post_title' => sanitize_text_field( $_POST['title'] ), 'post_excerpt' => sanitize_text_field( $_POST['caption'] ), 'post_content' => sanitize_textarea_field( $_POST['description'] ), ); wp_update_post( $post ); update_post_meta( $id, '_wp_attachment_image_alt', sanitize_text_field( $_POST['alt'] ) ); wp_send_json_success(); }
Security Fix
@@ -100,6 +100,10 @@ function acf_photo_gallery_edit_save() { check_ajax_referer( 'acf_photo_gallery_nonce', 'nonce' ); + if ( ! current_user_can( 'edit_posts' ) ) { + wp_send_json_error( array( 'message' => 'Permission denied' ), 403 ); + } + $id = intval( $_POST['id'] ); $post = array( 'ID' => $id,
Exploit Outline
To exploit this vulnerability, an attacker must first obtain a valid Subscriber-level account on the WordPress site. By navigating to an admin page (like /wp-admin/profile.php) or a frontend page where the ACF Photo Gallery script is localized, the attacker extracts the 'acf_photo_gallery_nonce' from the localized JavaScript object (e.g., window.acf_photo_gallery_js_obj). The attacker then sends a POST request to /wp-admin/admin-ajax.php with the action parameter 'acf_photo_gallery_edit_save', the extracted nonce, and the target attachment's ID. The payload includes new values for 'title', 'caption', 'alt', and 'description', which the plugin will apply to the specified media attachment without verifying if the user has permission to edit that post or media.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.