Gallery PhotoBlocks <= 1.3.2 - Authenticated (Contributor+) Stored Cross-Site Scripting
Description
The Gallery PhotoBlocks plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 1.3.2 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with contributor-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=1.3.2Source Code
WordPress.org SVNBased on the vulnerability details and the WordPress security knowledge base provided, here is a detailed exploitation research plan for **CVE-2026-24389: Gallery PhotoBlocks <= 1.3.2 - Authenticated (Contributor+) Stored Cross-Site Scripting**. --- ### 1. Vulnerability Summary **Gallery PhotoBloc…
Show full research plan
Based on the vulnerability details and the WordPress security knowledge base provided, here is a detailed exploitation research plan for CVE-2026-24389: Gallery PhotoBlocks <= 1.3.2 - Authenticated (Contributor+) Stored Cross-Site Scripting.
1. Vulnerability Summary
Gallery PhotoBlocks is a grid gallery plugin that allows users to create and manage visual galleries. In versions up to 1.3.2, the plugin fails to sufficiently sanitize or escape user-provided data when saving gallery configurations or block attributes. This allows a user with Contributor permissions or higher to inject malicious scripts (Stored XSS) into the gallery data. These scripts execute in the context of any user (including Administrators) who views the gallery on the frontend or manages it in the backend.
2. Attack Vector Analysis
- Endpoint: WordPress AJAX API (
/wp-admin/admin-ajax.php). - Action:
photoblocks_saveorpb_save_gallery(inferred from plugin slug and common patterns). - Parameter: Typically a JSON-encoded string or an array of block settings (e.g.,
data,gallery_data, orblocks). - Vulnerable Fields: Likely fields include block titles, descriptions, custom CSS areas, or link URL attributes that are later rendered in the gallery grid.
- Authentication: Authenticated (Contributor+). Contributor is sufficient as they generally have permissions to create or edit galleries/posts depending on plugin configuration.
- Preconditions: The plugin must be active. The attacker needs a valid session and a WordPress nonce for the specific AJAX action.
3. Code Flow (Inferred)
- Entry Point: The user triggers an AJAX request to save a gallery.
- Handler: The plugin registers an AJAX handler via
add_action('wp_ajax_photoblocks_save', ...). - Data Processing: The handler retrieves the gallery configuration from
$_POST. - Insecure Sink (Storage): The data is saved to the database (likely in
wp_postmetaunder a key like_photoblocks_data) usingupdate_post_meta()without rigorous sanitization (e.g., usingwp_ksesorsanitize_text_fieldon every sub-attribute). - Insecure Sink (Output): When the gallery is rendered via the
[photoblocks]shortcode or in the admin preview, the plugin echoes the stored attributes without context-appropriate escaping (e.g.,esc_attr()oresc_html()).
4. Nonce Acquisition Strategy
To exploit the AJAX endpoint, a valid nonce is required. Since we are testing as a Contributor, we can navigate to the gallery editor page to find it.
- Identify the Script: The plugin likely localizes data using
wp_localize_script. - Navigate to Admin: Use
browser_navigateto go to the PhotoBlocks gallery list or editor:/wp-admin/admin.php?page=photoblocks-galleries(inferred). - Extract Nonce: Use
browser_evalto extract the nonce from the global JavaScript object.- Inferred Variable Name:
window.photoblocks_obj?.nonceorwindow.pb_config?.nonce. - Action:
browser_eval("window.pb_config.nonce")(replacepb_configwith the actual localized variable found in the page source).
- Inferred Variable Name:
5. Exploitation Strategy
The plan involves injecting a script into a gallery attribute that will be rendered when the gallery is viewed.
Step 1: Create a Gallery (if none exists)
As a Contributor, create a new PhotoBlock gallery to obtain a gallery_id.
Step 2: Intercept/Identify the Save Request
Determine the exact structure of the save request by observing the "Save" action in the gallery editor.
- Payload Example (JSON):
{ "blocks": [ { "title": "Gallery Block <img src=x onerror=alert(document.domain)>", "description": "Exploit" } ] }
Step 3: Send Malicious HTTP Request
Using the http_request tool, send a POST request to admin-ajax.php.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
(Note: Replaceaction=pb_save_gallery&nonce=[NONCE]&id=[GALLERY_ID]&data=[URL_ENCODED_JSON_PAYLOAD]pb_save_galleryanddatawith the actual parameter names discovered).
Step 4: Trigger XSS
Place the gallery shortcode on a public page and view it as an Administrator.
- Shortcode:
[photoblocks id="[GALLERY_ID]"]
6. Test Data Setup
- User: Create a user with the Contributor role.
- Post: Create a new page/post to host the gallery shortcode:
wp post create --post_type=page --post_status=publish --post_title="Gallery Test" --post_content='[photoblocks id="1"]'(adjust ID as necessary).
7. Expected Results
- The AJAX request should return a success response (e.g.,
{"success": true}). - When navigating to the "Gallery Test" page as an Admin, an alert box showing the document domain should appear.
- In the HTML source of the rendered gallery, the payload
<img src=x onerror=alert(document.domain)>should appear unescaped within an attribute or tag.
8. Verification Steps
- Check Database: Verify the payload is stored in the
postmetatable.wp db query "SELECT meta_value FROM wp_postmeta WHERE meta_key = '_photoblocks_data' AND post_id = [GALLERY_ID]" - Verify Frontend Execution:
Usebrowser_navigateto the page containing the shortcode and check for the alert or the presence of the injected string in the DOM.
9. Alternative Approaches
- Custom CSS Sink: If the plugin allows "Custom CSS" per gallery, inject:
}</style><script>alert(1)</script>. - Image Metadata: If the plugin pulls titles from the Media Library, try injecting XSS into the image "Title" or "Caption" fields in the Media Library, then adding that image to a PhotoBlock.
- Settings API: Check if the plugin has global settings accessible to Contributors (unlikely, but worth checking
register_settingcalls).
Technical Identifiers (Inferred - To be verified by agent)
- AJAX Actions:
pb_save_gallery,pb_get_gallery,photoblocks_save. - JS Localized Key:
pb_config,photoblocks_admin. - Post Meta Key:
_photoblocks_data,_pb_settings. - Shortcode:
[photoblocks],[photoblock].
Summary
The Gallery PhotoBlocks plugin for WordPress is vulnerable to Stored Cross-Site Scripting due to insufficient input sanitization and output escaping of gallery block attributes. Authenticated attackers with Contributor-level permissions or higher can inject malicious JavaScript into gallery settings via AJAX, which executes when the gallery is rendered for visitors or administrators.
Exploit Outline
1. Authenticate as a Contributor-level user and navigate to the PhotoBlocks gallery management interface to extract the localized security nonce (likely found in a global JS object like `pb_config.nonce`). 2. Identify the gallery ID of an existing gallery or create a new one. 3. Prepare a malicious JSON payload for the gallery configuration where block attributes (e.g., 'title' or 'description') contain an XSS payload such as `<img src=x onerror=alert(document.domain)>`. 4. Send an authenticated POST request to `/wp-admin/admin-ajax.php` with the `action` set to `pb_save_gallery`, the acquired `nonce`, the `id` of the gallery, and the malicious payload in the `data` parameter. 5. Embed the gallery shortcode `[photoblocks id="GALLERY_ID"]` into a post or page. 6. The script will execute whenever an Administrator or any other user views the affected page.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.