Orbit Fox: Duplicate Page, Menu Icons, SVG Support, Cookie Notice, Custom Fonts & More <= 3.0.6 - Authenticated (Administrator+) Stored Cross-Site Scripting via 'menu-item-icon' Parameter
Description
The Orbit Fox: Duplicate Page, Menu Icons, SVG Support, Cookie Notice, Custom Fonts & More plugin for WordPress is vulnerable to Stored Cross-Site Scripting via admin settings in all versions up to, and including, 3.0.6 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with administrator-level permissions and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page. This only affects multi-site installations and installations where unfiltered_html has been disabled.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=3.0.6What Changed in the Fix
Changes introduced in v3.0.7
Source Code
WordPress.org SVNThis research plan outlines the steps required to demonstrate the Stored Cross-Site Scripting (XSS) vulnerability in the **Orbit Fox Companion** plugin (CVE-2026-11358). ## 1. Vulnerability Summary The Orbit Fox plugin is vulnerable to Stored XSS via the `menu-item-icon` parameter. The plugin provi…
Show full research plan
This research plan outlines the steps required to demonstrate the Stored Cross-Site Scripting (XSS) vulnerability in the Orbit Fox Companion plugin (CVE-2026-11358).
1. Vulnerability Summary
The Orbit Fox plugin is vulnerable to Stored XSS via the menu-item-icon parameter. The plugin provides a "Menu Icons" module that allows users to attach icons to navigation menu items. When a menu item is saved, the icon identifier is stored in the post meta. When the WordPress Navigation Menu editor (wp-admin/nav-menus.php) is loaded, the plugin uses a custom Walker class (Menu_Icons_OBFX_Walker) to render the menu item settings. This Walker fails to sanitize or escape the stored icon value before outputting it into a hidden HTML input field, allowing an attacker with menu-editing permissions (typically Administrator) to inject arbitrary scripts.
2. Attack Vector Analysis
- Target Endpoint:
wp-admin/nav-menus.php - Vulnerable Parameter:
menu-item-icon[<MENU_ITEM_ID>] - Authentication Level: Authenticated Administrator (or any user with
edit_theme_optionscapability). - Preconditions:
- The "Menu Icons" module must be active (active by default upon installation).
- The environment must have
unfiltered_htmldisabled (standard for Multisite Administrators or ifDISALLOW_UNFILTERED_HTMLis true).
3. Code Flow
- Input (Storage): When a user saves a menu, WordPress triggers the
wp_update_nav_menu_itemhook. The plugin'sMenu_Icons_OBFX_Module::save_fields(inobfx_modules/menu-icons/init.php) retrieves the icon value from$_POST['menu-item-icon'][$menu_item_db_id]and saves it to the database usingupdate_post_meta($menu_item_db_id, 'obfx_menu_icon', $icon). - Retrieval: When the Nav Menu editor is loaded,
Menu_Icons_OBFX_Module::show_menuis called via thewp_setup_nav_menu_itemfilter. It retrieves the meta:$icon = get_post_meta( $menu->ID, 'obfx_menu_icon', true );and assigns it to$menu->icon. - Sink (Execution): The plugin registers
Menu_Icons_OBFX_Walkerfor the menu editor. Inobfx_modules/menu-icons/inc/class-menu-icons-obfx-walker.php, thestart_elmethod renders the field:
The$icon = isset( $item->icon ) ? $item->icon : ''; $output .= sprintf( '<input type="hidden" name="menu-item-icon[%d]" id="menu-item-icon-%d" value="%s">', $item->ID, $item->ID, $icon );$iconvariable is injected into thevalueattribute using%swithout any escaping (likeesc_attr()), allowing an attacker to break out of the attribute and inject tags.
4. Nonce Acquisition Strategy
To update the menu, a valid WordPress nonce for the update-nav_menu action is required.
- Identify the Source: The nonce is generated by WordPress on the
wp-admin/nav-menus.phppage inside a hidden input field with the IDupdate-nav-menu-nonce. - Extraction:
- Use
browser_navigateto go towp-admin/nav-menus.php. - Use
browser_evalto extract the nonce and the ID of an existing menu item:{ nonce: document.querySelector('#update-nav-menu-nonce')?.value, menuId: document.querySelector('#nav-menu-meta-object-id')?.value, // Get the ID of the first menu item in the list firstMenuItemId: document.querySelector('.menu-item-settings')?.id?.split('-')?.pop() }
- Use
5. Exploitation Strategy
- Setup: Ensure at least one menu and one menu item exist.
- Payload:
"><script>alert(document.domain)</script> - Trigger Request: Send a POST request to
wp-admin/nav-menus.phpto save the menu item with the malicious icon value.- URL:
http://<target>/wp-admin/nav-menus.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body Parameters:
action:updatenav-menu-data: (Standard menu structure string, can be captured from a legitimate save or left minimal)update-nav-menu-nonce:<EXTRACTED_NONCE>menu:<MENU_ID>menu-item-icon[<ITEM_ID>]:"><script>alert(document.domain)</script>
- URL:
- Execution: After the request completes, navigate back to
wp-admin/nav-menus.php. The script will execute when the Walker renders the hidden input for that specific menu item.
6. Test Data Setup
- Create an administrator user.
- Activate the
themeisle-companionplugin. - Use
wp-clito ensure a menu exists:wp menu create "Test Menu" wp menu item add-custom "Test Menu" "Home" "http://localhost/" - Verify the "Menu Icons" module is active in Orbit Fox settings (it is
active_default = trueininit.php).
7. Expected Results
- The POST request should return a
302 Redirectback tonav-menus.php. - Upon viewing
nav-menus.php, the HTML source for the specific menu item will contain:<input type="hidden" name="menu-item-icon[ID]" ... value=""><script>alert(document.domain)</script>"> - An alert box showing the domain will appear in the browser.
8. Verification Steps
After performing the exploit via http_request, verify the payload is stored in the database:
# Replace <ITEM_ID> with the actual ID used
wp post meta get <ITEM_ID> obfx_menu_icon
Confirm the output exactly matches the payload: "><script>alert(document.domain)</script>.
9. Alternative Approaches
If the nav-menus.php POST structure is too complex, the payload can also be injected via the wp_ajax_obfx_update_module_options AJAX action if the specific module exposes the icon settings there. However, the nav-menus.php vector is the most direct path as it leverages the primary functionality of the Menu Icons module.
Summary
The Orbit Fox plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'menu-item-icon' parameter in the Menu Icons module. This occurs because the plugin fails to sanitize or escape the icon identifier when rendering the navigation menu editor, allowing authenticated administrators to inject arbitrary scripts that execute when a user views the menu settings page.
Vulnerable Code
// obfx_modules/menu-icons/inc/class-menu-icons-obfx-walker.php line 22 public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) { parent::start_el( $output, $item, $depth, $args, $id ); $icon = isset( $item->icon ) ? $item->icon : ''; $output .= sprintf( '<input type="hidden" name="menu-item-icon[%d]" id="menu-item-icon-%d" value="%s">', $item->ID, $item->ID, $icon ); } --- // obfx_modules/menu-icons/init.php line 107 public function show_menu( $menu ) { $icon = get_post_meta( $menu->ID, 'obfx_menu_icon', true ); if ( ! empty( $icon ) ) { $menu->icon = $icon; if ( ! is_admin() ) { // ... $menu->title = sprintf( '<i class="obfx-menu-icon %s %s"></i>%s', $prefix, $icon, $menu->title ); } } return $menu; }
Security Fix
@@ -22,6 +22,6 @@ public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) { parent::start_el( $output, $item, $depth, $args, $id ); $icon = isset( $item->icon ) ? $item->icon : ''; - $output .= sprintf( '<input type="hidden" name="menu-item-icon[%d]" id="menu-item-icon-%d" value="%s">', $item->ID, $item->ID, $icon ); + $output .= sprintf( '<input type="hidden" name="menu-item-icon[%d]" id="menu-item-icon-%d" value="%s">', $item->ID, $item->ID, esc_attr( $icon ) ); } } @@ -115,7 +115,7 @@ $array = explode( '-', $icon ); $prefix = reset( $array ); $prefix = apply_filters( 'obfx_menu_icons_icon_class', $prefix, $icon ); - $menu->title = sprintf( '<i class="obfx-menu-icon %s %s"></i>%s', $prefix, $icon, $menu->title ); + $menu->title = sprintf( '<i class="obfx-menu-icon %s %s"></i>%s', esc_attr( $prefix ), esc_attr( $icon ), $menu->title ); } } return $menu;
Exploit Outline
The exploit targets the navigation menu editor in the WordPress admin panel. An authenticated attacker with at least Administrator privileges (or permissions to manage menus) can inject a payload into the 'menu-item-icon' field. To execute this, the attacker first navigates to wp-admin/nav-menus.php to retrieve a valid 'update-nav-menu-nonce'. They then submit a POST request to update a specific menu item, setting the 'menu-item-icon[ITEM_ID]' parameter to a payload designed to break out of an HTML attribute (e.g., "><script>alert(1)</script>"). The payload is stored in the database. When the menu editor is subsequently reloaded, the vulnerable custom Walker (Menu_Icons_OBFX_Walker) renders the raw payload into the 'value' attribute of a hidden input field, triggering the script execution.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.