CVE-2025-15019

BIALTY - Bulk Image Alt Text (Alt tag, Alt Attribute) with Yoast SEO + WooCommerce <= 2.2.1 - Authenticated (Contributor+) Stored Cross-Site Scripting

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
6.4
CVSS Score
6.4
CVSS Score
medium
Severity
2.2.2
Patched in
1d
Time to patch

Description

The BIALTY - Bulk Image Alt Text (Alt tag, Alt Attribute) with Yoast SEO + WooCommerce plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'bialty_cs_alt' post meta in all versions up to, and including, 2.2.1 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 an administrator accesses the post editor.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=2.2.1
PublishedJanuary 8, 2026
Last updatedJanuary 9, 2026

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2025-15019 ## 1. Vulnerability Summary The **Bulk Auto Image Alt Text (BIALTY)** plugin (<= 2.2.1) is vulnerable to **Stored Cross-Site Scripting (XSS)**. The vulnerability exists because the plugin fails to sanitize the `bialty_cs_alt` post meta value when it is …

Show full research plan

Exploitation Research Plan - CVE-2025-15019

1. Vulnerability Summary

The Bulk Auto Image Alt Text (BIALTY) plugin (<= 2.2.1) is vulnerable to Stored Cross-Site Scripting (XSS). The vulnerability exists because the plugin fails to sanitize the bialty_cs_alt post meta value when it is saved and fails to escape it when it is rendered within the WordPress post editor. A user with Contributor level permissions or higher can create a post, inject a malicious script into this meta field, and have that script execute in the browser of any user (specifically an Administrator) who later edits that post.

2. Attack Vector Analysis

  • Vulnerable Endpoint: wp-admin/post.php (Standard WordPress post update handler).
  • Vulnerable Parameter: bialty_cs_alt (Typically sent via POST during post save/update).
  • Authentication Level: Contributor or higher. Contributors can edit their own posts and manage post meta associated with them.
  • Preconditions: The plugin must be active. The attacker needs access to the post editor for a post type that supports the BIALTY meta box (usually post, page, or product).

3. Code Flow (Inferred)

  1. Input Registration: The plugin registers a metabox in the post editor via the add_meta_boxes hook.
  2. Display (Sink): The metabox callback function retrieves the meta value using get_post_meta($post->ID, 'bialty_cs_alt', true). It likely outputs this value into an HTML input field (e.g., <input value="...">) without using esc_attr().
  3. Saving (Source): The plugin listens for post save events via the save_post or wp_insert_post hook.
  4. Processing: The handler function (e.g., bialty_save_meta_box_data) checks if $_POST['bialty_cs_alt'] is set.
  5. Storage: It calls update_post_meta($post_id, 'bialty_cs_alt', $_POST['bialty_cs_alt']) without applying sanitization functions like sanitize_text_field().

4. Nonce Acquisition Strategy

The BIALTY plugin likely uses a custom nonce within its metabox to validate the meta submission, in addition to the standard WordPress _wpnonce.

  1. Create Content: As a Contributor, create a new draft post:
    wp post create --post_type=post --post_status=draft --post_title="XSS Test" --post_author=CONTRIBUTOR_ID
  2. Navigate to Editor: Use the browser_navigate tool to go to the edit page for that post: /wp-admin/post.php?post=POST_ID&action=edit.
  3. Extract Nonce: The metabox will contain a hidden nonce field. Use browser_eval to find the BIALTY-specific nonce:
    • browser_eval("document.querySelector('input[name*=\"bialty\"]')?.value")
    • Alternatively, search the HTML for a field likely named bialty_meta_box_nonce or similar.
  4. Standard Nonce: The standard _wpnonce for the editpost action is also required and can be found via:
    browser_eval("document.querySelector('#_wpnonce')?.value")

5. Exploitation Strategy

Step 1: Authentication and Post Creation

  1. Authenticate as a Contributor.
  2. Create a post to obtain a post_ID.

Step 2: Injecting the Payload

Send a POST request to wp-admin/post.php to update the post meta.

  • URL: https://TARGET/wp-admin/post.php
  • Method: POST
  • Content-Type: application/x-www-form-urlencoded
  • Body Parameters:
    • action: editpost
    • post_ID: [POST_ID]
    • _wpnonce: [EXTRACTED_WP_NONCE]
    • bialty_meta_box_nonce: [EXTRACTED_BIALTY_NONCE] (if applicable)
    • bialty_cs_alt: "><script>alert(document.cookie)</script>
    • post_title: XSS Test

Step 3: Triggering the Execution

  1. Log in as an Administrator.
  2. Navigate to the post editor for the infected post: /wp-admin/post.php?post=[POST_ID]&action=edit.
  3. The script will execute because the value is rendered unsanitized in the BIALTY metabox field.

6. Test Data Setup

  1. Install and activate the bulk-image-alt-text-with-yoast plugin (version <= 2.2.1).
  2. Create a user with the contributor role.
  3. (Optional) Install Yoast SEO or WooCommerce if the plugin requires their presence to activate the meta boxes (the vulnerability description suggests the plugin works with them).

7. Expected Results

  • The update_post_meta call succeeds.
  • The database now contains the raw HTML payload in the wp_postmeta table for the key bialty_cs_alt.
  • When an Admin views the post editor, the HTML source of the page shows the injected payload breaking out of the input attribute:
    <input ... value=""><script>alert(document.cookie)</script>">
  • A JavaScript alert containing the session cookie appears in the Admin's browser.

8. Verification Steps

  1. Check Database via CLI:
    wp post meta get [POST_ID] bialty_cs_alt
    Confirm the output matches the payload exactly.
  2. Verify Payload in HTML:
    Navigate to the edit page as Admin and check if the payload exists in the response body.
    http_request(url="/wp-admin/post.php?post=POST_ID&action=edit", method="GET")
    Check the response for the string: "><script>alert(document.cookie)</script>.

9. Alternative Approaches

  • WooCommerce Product: If the standard post metabox is not vulnerable, try the same process with a product post type if WooCommerce is installed, as the plugin specifically targets WooCommerce.
  • AJAX Save: Check if the plugin has an AJAX handler for "Bulk" operations that might update the meta field via admin-ajax.php. Search for wp_ajax_bialty_ actions in the code.
  • Payload Variations:
    • " onmouseover="alert(1) (Attribute injection)
    • </textarea><script>alert(1)</script> (If the field is a textarea)
Research Findings
Static analysis — not yet PoC-verified

Summary

The BIALTY plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'bialty_cs_alt' post meta field. This occurs because the plugin fails to sanitize the meta value upon saving and fails to escape it when rendering it within a metabox in the WordPress post editor. This allows authenticated users with Contributor-level access to inject malicious scripts that execute in the browser of an administrator viewing the affected post.

Vulnerable Code

// Inferred metabox rendering function
$bialty_cs_alt = get_post_meta($post->ID, 'bialty_cs_alt', true);
?>
<div class="bialty-metabox-field">
    <label for="bialty_cs_alt">Custom Alt Text:</label>
    <input type="text" name="bialty_cs_alt" id="bialty_cs_alt" value="<?php echo $bialty_cs_alt; ?>" />
</div>
<?php

---

// Inferred save_post handler function
if (isset($_POST['bialty_cs_alt'])) {
    update_post_meta($post_id, 'bialty_cs_alt', $_POST['bialty_cs_alt']);
}

Security Fix

--- a/includes/class-bialty-metabox.php
+++ b/includes/class-bialty-metabox.php
@@ -10,7 +10,7 @@
-    <input type="text" name="bialty_cs_alt" id="bialty_cs_alt" value="<?php echo $bialty_cs_alt; ?>" />
+    <input type="text" name="bialty_cs_alt" id="bialty_cs_alt" value="<?php echo esc_attr($bialty_cs_alt); ?>" />
 
--- a/includes/class-bialty-save.php
+++ b/includes/class-bialty-save.php
@@ -20,5 +20,5 @@
-if (isset($_POST['bialty_cs_alt'])) {
-    update_post_meta($post_id, 'bialty_cs_alt', $_POST['bialty_cs_alt']);
+if (isset($_POST['bialty_cs_alt'])) {
+    update_post_meta($post_id, 'bialty_cs_alt', sanitize_text_field($_POST['bialty_cs_alt']));
 }

Exploit Outline

1. Authenticate as a Contributor level user. 2. Create a new post or edit an existing one. 3. Identify the BIALTY metabox in the editor or prepare a POST request to wp-admin/post.php with action=editpost. 4. Include the parameter 'bialty_cs_alt' in the POST body with a payload designed to break out of an HTML attribute, such as: "><script>alert(document.cookie)</script>. 5. Submit the request to save the post. The payload will be stored unsanitized in the wp_postmeta table. 6. As an Administrator, navigate to the post editor for the infected post. The script will execute because the plugin echoes the 'bialty_cs_alt' value directly into the 'value' attribute of an input tag without escaping.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.