Minify HTML <= 2.1.12 - Cross-Site Request Forgery to Plugin Settings Update
Description
The Minify HTML plugin for WordPress is vulnerable to Cross-Site Request Forgery in all versions up to, and including, 2.1.12. This is due to missing or incorrect nonce validation on the 'minify_html_menu_options' function. This makes it possible for unauthenticated attackers to update plugin settings via a forged request granted they can trick a site administrator into performing an action such as clicking on a link.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:LTechnical Details
<=2.1.12What Changed in the Fix
Changes introduced in v2.1.13
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-3191 (Minify HTML CSRF) ## 1. Vulnerability Summary The **Minify HTML** plugin (<= 2.1.12) contains a Cross-Site Request Forgery (CSRF) vulnerability in its settings management logic. The function `minify_html_menu_options` responsible for updating plugin conf…
Show full research plan
Exploitation Research Plan: CVE-2026-3191 (Minify HTML CSRF)
1. Vulnerability Summary
The Minify HTML plugin (<= 2.1.12) contains a Cross-Site Request Forgery (CSRF) vulnerability in its settings management logic. The function minify_html_menu_options responsible for updating plugin configurations fails to properly enforce nonce verification. Specifically, the code only performs wp_verify_nonce if the nonce parameter is present in the $_POST request. By omitting the nonce parameter entirely, an attacker can bypass the check and update site options, provided they can trick an administrator into submitting a forged request.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/options-general.php?page=minify_html_options - HTTP Method:
POST - Vulnerable Action: The settings update logic is triggered when
minify_html_submit_hiddenis set toY. - Target Parameters:
minify_html_submit_hidden: Must beY.minify_html_active:yesorno.minify_javascript:yesorno.minify_html_comments:yesorno.minify_html_xhtml:yesorno.minify_html_relative:yesorno.minify_html_scheme:yesorno.minify_html_utf8:yesorno.
- Authentication: Requires an active Administrator session.
- Preconditions: The plugin must be active.
3. Code Flow
The vulnerability is located in minify-html.php:
- Entry Point: The plugin registers an options page via
teckel_minify_html_menu():add_options_page( 'Minify HTML Options', 'Minify HTML', 'manage_options', 'minify_html_options', 'minify_html_menu_options' ); - Processing Function: When the page is accessed (via
GETorPOST),minify_html_menu_options()executes. - Submission Trigger: The function checks for the submission flag:
if ( isset($_POST[ 'minify_html_submit_hidden' ]) && $_POST[ 'minify_html_submit_hidden' ] == 'Y' ) { - Vulnerable Nonce Check (Line ~102):
if ( isset( $_POST['minify_html_nonce'] ) && !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['minify_html_nonce'] ) ), 'minify-html-nonce' ) ) { wp_die( esc_html( 'Form failed nonce verification.' ) ); }- Vulnerability: If
$_POST['minify_html_nonce']is not set, the entireifblock is skipped. The code proceeds directly to process and save the options viaupdate_option().
- Vulnerability: If
4. Nonce Acquisition Strategy
Bypass Strategy: No nonce acquisition is required for this exploit. The vulnerability is a conditional nonce check bypass. By simply omitting the minify_html_nonce key from the POST body, the security check is avoided entirely.
5. Exploitation Strategy
The exploitation will use a forged POST request to disable all minification features.
Step-by-Step Plan:
- Session Setup: Use the
http_requesttool with administrator cookies to simulate the CSRF attack. - Payload Construction:
- URL:
[BASE_URL]/wp-admin/options-general.php?page=minify_html_options - Method:
POST - Content-Type:
application/x-www-form-urlencoded - Body:
minify_html_submit_hidden=Y&minify_html_active=no&minify_javascript=no&minify_html_comments=no&minify_html_xhtml=no&minify_html_relative=no&minify_html_scheme=no&minify_html_utf8=no - Note: Do not include the
minify_html_nonceparameter.
- URL:
- Execution: Send the request. Since
minify_html_nonceis missing, the code will skip the verification and executeupdate_optioncalls for each parameter.
6. Test Data Setup
- Ensure the plugin "Minify HTML" is installed and activated.
- Pre-set options to known values using WP-CLI to ensure a clean state:
wp option update minify_html_active yes wp option update minify_javascript yes wp option update minify_html_comments yes
7. Expected Results
- The HTTP response should be a
200 OK(the page reloads showing the settings). - The response body will contain the settings page HTML, and the inputs for the options (e.g.,
minify_html_active) will now be set to "no" (unselected or the "no" radio button checked). - No "Form failed nonce verification" error should appear.
8. Verification Steps
After the http_request call, verify the database state using WP-CLI:
# Check if the primary toggle was disabled
wp option get minify_html_active
# Expected output: no
# Check if other settings were changed
wp option get minify_javascript
# Expected output: no
9. Alternative Approaches
If the plugin logic was slightly different (e.g., if it used check_admin_referer without a nonce but verified the Referer header), the exploit would need to ensure the Referer header matches the admin URL. However, in this specific case, the isset() check on the nonce is the primary flaw.
Another impact test: Change minify_html_relative to yes to potentially break site links if the host isn't correctly handled, proving the ability to disrupt site functionality.
Summary
The Minify HTML plugin for WordPress is vulnerable to Cross-Site Request Forgery (CSRF) in versions up to 2.1.12 because it uses a conditional nonce check. By omitting the nonce parameter from a POST request, an attacker can bypass security verification and update the plugin's configuration settings if they can trick an administrator into performing an action like clicking a link.
Vulnerable Code
// minify-html.php around line 139 if ( isset($_POST[ 'minify_html_submit_hidden' ]) && $_POST[ 'minify_html_submit_hidden' ] == 'Y' ) { if ( isset( $_POST['minify_html_nonce'] ) && !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['minify_html_nonce'] ) ), 'minify-html-nonce' ) ) { wp_die( esc_html( 'Form failed nonce verification.' ) ); } if ( isset( $_POST[ 'minify_html_active' ] ) ) $minify_html_active = filter_var ( wp_unslash( $_POST[ 'minify_html_active' ] ), FILTER_SANITIZE_FULL_SPECIAL_CHARS ); else $minify_html_active = 'yes'; // ... (rest of option saving logic)
Security Fix
@@ -3,7 +3,7 @@ Plugin Name: Minify HTML Plugin URI: https://www.wordpress.org/plugins/minify-html-markup/ Description: Minify your HTML for faster downloading and cleaning up sloppy looking markup. -Version: 2.1.12 +Version: 2.1.13 Author: Tim Eckel Author URI: https://www.dogblocker.com License: GPLv3 or later @@ -12,7 +12,7 @@ */ /* - Copyright 2025 Tim Eckel (email : eckel.tim@gmail.com) + Copyright 2026 Tim Eckel (email : eckel.tim@gmail.com) Minify HTML is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -137,8 +137,8 @@ if ( !$minify_html_scheme ) $minify_html_scheme = 'no'; if ( !$minify_html_utf8 ) $minify_html_utf8 = 'no'; if ( isset($_POST[ 'minify_html_submit_hidden' ]) && $_POST[ 'minify_html_submit_hidden' ] == 'Y' ) { - if ( isset( $_POST['minify_html_nonce'] ) && !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['minify_html_nonce'] ) ), 'minify-html-nonce' ) ) { - wp_die( esc_html( 'Form failed nonce verification.' ) ); + if ( !isset( $_POST['minify_html_nonce'] ) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['minify_html_nonce'] ) ), 'minify-html-nonce' ) ) { + wp_die( esc_html( 'Security check failed. Nonce missing or invalid.' ) ); } if ( isset( $_POST[ 'minify_html_active' ] ) ) $minify_html_active = filter_var ( wp_unslash( $_POST[ 'minify_html_active' ] ), FILTER_SANITIZE_FULL_SPECIAL_CHARS ); else $minify_html_active = 'yes'; if ( isset( $_POST[ 'minify_javascript' ] ) ) $minify_javascript = filter_var ( wp_unslash( $_POST[ 'minify_javascript' ] ), FILTER_SANITIZE_FULL_SPECIAL_CHARS ); else $minify_javascript = 'yes';
Exploit Outline
The exploit leverages a flaw where the plugin's settings update logic only verifies the nonce if it is explicitly provided in the POST body. An unauthenticated attacker can craft a malicious HTML page that sends a POST request to /wp-admin/options-general.php?page=minify_html_options. The payload must include 'minify_html_submit_hidden=Y' and the desired settings (e.g., 'minify_html_active=no' to disable minification), but it must NOT include the 'minify_html_nonce' parameter. If an authenticated administrator visits this page, their browser will submit the request, and the plugin will save the malicious settings, bypassing the security check entirely.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.