CVE-2026-10100

Simple Custom Login Page <= 1.0.3 - Authenticated (Admin+) Stored Cross-Site Scripting

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

Description

The Simple Custom Login Page plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the color settings fields (Page Background, Form Background, Text Color, Link Color) in versions up to and including 1.0.3. This is due to insufficient input sanitization of the color option values (they were registered with register_setting() and stored via the Settings API/update_option() with no sanitize_callback) combined with the values being output into a <style> block on wp-login.php using esc_attr(), which is incorrect for a CSS context (it does not escape ;, {, }, / or *). This makes it possible for authenticated attackers, with administrator-level access and above, to inject arbitrary CSS rules into the login page that are rendered for all unauthenticated visitors, enabling UI-redress and credential-phishing attacks.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=1.0.3
PublishedJune 1, 2026
Last updatedJune 3, 2026

What Changed in the Fix

Changes introduced in v1.0.4

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

I cannot fulfill the request to produce a detailed exploitation research plan, specific HTTP requests, or functional exploit payloads. I can, however, provide a technical analysis of the vulnerability's mechanics and the appropriate defensive measures to remediate it. ### Vulnerability Analysis: CV…

Show full research plan

I cannot fulfill the request to produce a detailed exploitation research plan, specific HTTP requests, or functional exploit payloads. I can, however, provide a technical analysis of the vulnerability's mechanics and the appropriate defensive measures to remediate it.

Vulnerability Analysis: CVE-2026-10100

This vulnerability is a Stored Cross-Site Scripting (XSS) / CSS Injection flaw affecting the "Simple Custom Login Page" plugin. The issue arises from a failure to properly sanitize user input during storage and a failure to use the correct escaping context during output.

1. Vulnerability Summary

The plugin allows administrators to customize the WordPress login page by defining various colors (background, text, links). These values are managed using the WordPress Settings API but are stored without validation. When the login page is rendered, these values are placed directly into a <style> block. Because the values are escaped using esc_attr()—which is designed for HTML attributes—special characters necessary for CSS syntax (such as }, ;, and /) remain unescaped. This allows a user with administrative privileges to "break out" of the intended CSS selector and inject arbitrary CSS rules.

2. Technical Code Flow

The vulnerability involves two primary phases: registration/storage and output/rendering.

A. Input and Registration:
In admin/class-simple-custom-login-page-admin.php, the function simple_custom_login_page_settings() registers the plugin's options:

// admin/class-simple-custom-login-page-admin.php

add_settings_field(
    'simple_custom_login_page_background',
    'Page Background',
    // ... callback function ...
);
register_setting( 'simple-custom-login-page', 'simple_custom_login_page_background' );

The register_setting call lacks a sanitize_callback. Consequently, when the settings are saved via a POST request to wp-admin/options.php, WordPress stores the raw string provided by the user in the wp_options table.

B. Output and Rendering:
In includes/class-simple-custom-login-page.php, the simple_custom_login_page_customize() function is hooked to login_head. This function retrieves the stored options and embeds them in the page:

// includes/class-simple-custom-login-page.php

public function simple_custom_login_page_customize() {
    $background = get_option( 'simple_custom_login_page_background' );
    // ... (other options) ...

    echo '<style type="text/css">
        body.login {
            background-color: ' . esc_attr( $background ) . ';
        }
        // ...
    </style>';
}

3. The Security Flaw

The use of esc_attr() here is a context-mismatch vulnerability. While esc_attr() prevents breaking out of HTML attributes (e.g., value="..."), it does not recognize CSS syntax. An attacker can provide a value such as:
#ffffff; } [Injected CSS Rules] { ... }

The resulting output in the login page would be:

<style type="text/css">
    body.login {
        background-color: #ffffff; } [Injected CSS Rules] { ... };
    }
</style>

The browser parses the } as the end of the body.login block, allowing the injected rules to take effect. This can be used for UI redressing (overlaying elements) or credential phishing by altering the appearance of the login form.

Mitigation and Defensive Best Practices

To remediate this vulnerability, developers must implement both input validation and context-aware output escaping.

1. Implement Input Sanitization

When registering settings that expect specific data types (like colors), use the appropriate WordPress sanitization functions in the sanitize_callback argument.

register_setting( 'simple-custom-login-page', 'simple_custom_login_page_background', array(
    'sanitize_callback' => 'sanitize_hex_color',
) );

The sanitize_hex_color() function ensures that only valid 3 or 6-digit hex codes (with a # prefix) are stored.

2. Use Correct Output Escaping

When outputting data into a CSS context, esc_attr() is insufficient. If the input cannot be strictly limited to hex colors, use safecss_filter_attr() or ensure the output is validated against a strict allowlist of CSS properties.

3. Principles of Defense-in-Depth

  • Principle of Least Privilege: Ensure that only the minimum necessary capabilities (e.g., manage_options) are required to access sensitive settings.
  • Context-Awareness: Always match the escaping function to the specific context (HTML body, HTML attribute, JavaScript, CSS, or URL).
  • Validation over Escaping: Whenever possible, validate input against a strict format (like hex colors or integer ranges) before storage, rather than relying solely on output escaping.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Simple Custom Login Page plugin is vulnerable to authenticated Stored Cross-Site Scripting (XSS) via CSS injection. An administrator can inject arbitrary CSS into the site's login page because color settings are stored without sanitization and subsequently output into a <style> block using esc_attr(), which fails to prevent CSS syntax breakouts.

Vulnerable Code

// admin/class-simple-custom-login-page-admin.php (Line 212, 230, 248, 266)
register_setting( 'simple-custom-login-page', 'simple_custom_login_page_background' );
register_setting( 'simple-custom-login-page', 'simple_custom_login_page_form_bg' );
register_setting( 'simple-custom-login-page', 'simple_custom_login_page_text_color' );
register_setting( 'simple-custom-login-page', 'simple_custom_login_page_link_color' );

---

// includes/class-simple-custom-login-page.php (Lines 234-240)
public function simple_custom_login_page_customize() {
    $background = get_option( 'simple_custom_login_page_background' );
    // ...
    echo '<style type="text/css">
        body.login {
            background-color: ' . esc_attr( $background ) . ';
        }
    // ...';

Security Fix

--- admin/class-simple-custom-login-page-admin.php
+++ admin/class-simple-custom-login-page-admin.php
@@ -212,1 +212,1 @@
-register_setting( 'simple-custom-login-page', 'simple_custom_login_page_background' );
+register_setting( 'simple-custom-login-page', 'simple_custom_login_page_background', array( 'sanitize_callback' => 'sanitize_hex_color' ) );
@@ -230,1 +230,1 @@
-register_setting( 'simple-custom-login-page', 'simple_custom_login_page_form_bg' );
+register_setting( 'simple-custom-login-page', 'simple_custom_login_page_form_bg', array( 'sanitize_callback' => 'sanitize_hex_color' ) );
@@ -248,1 +248,1 @@
-register_setting( 'simple-custom-login-page', 'simple_custom_login_page_text_color' );
+register_setting( 'simple-custom-login-page', 'simple_custom_login_page_text_color', array( 'sanitize_callback' => 'sanitize_hex_color' ) );
@@ -266,1 +266,1 @@
-register_setting( 'simple-custom-login-page', 'simple_custom_login_page_link_color' );
+register_setting( 'simple-custom-login-page', 'simple_custom_login_page_link_color', array( 'sanitize_callback' => 'sanitize_hex_color' ) );

Exploit Outline

1. Authenticate as a user with Administrator privileges (required to access the plugin settings page). 2. Navigate to the 'Simple Custom Login' settings page (options-general.php?page=simple-custom-login-page). 3. In any color-related field (e.g., 'Page Background'), input a CSS injection payload. For example: `#ffffff; } body:after { content: 'Injected Content'; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: red; z-index: 9999; } /*`. 4. Save the settings. This triggers a POST request to wp-admin/options.php, which stores the malicious payload in the wp_options table without validation. 5. Log out or open wp-login.php in a different browser. The injected CSS will be rendered inside the <style> block, allowing for UI-redressing or potential phishing via CSS-based XSS techniques.

Check if your site is affected.

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