Codeinwp / Codeinwp/neve

Mobile nav dropdown aria-label can be corrupted by third-party wp_kses_allowed_html filters

Open
#4,623 0 comments 0 reactions 1 assignee View on GitHub

@Alexia-Soare is already working on this.

Since Sep 18, 2026.

customer report
Dominant language
PHP
Stars
306
Forks
88
Avg merge
2d 16h
Merged PRs (30d)
12

Description

The mobile sidebar dropdown toggle button's aria-label is built using wp_filter_nohtml_kses(), which is not resilient to third-party plugins that hook wp_kses_allowed_html incorrectly. When such a plugin adds allowed tags without respecting WordPress's reserved 'strip' context, the wrapper Neve adds around the menu title survives instead of being stripped, producing a corrupted, HTML-tag-filled aria-label on every dropdown menu item.

Steps to reproduce:

  1. Activate Neve, create a menu with at least one item that has children (e.g. "Shop" with a submenu), assign it to the Primary location.
  2. Install and activate the "Booster for WooCommerce" plugin (woocommerce-jetpack) — any recent version.
  3. View the mobile menu markup (view-source, or inspect the dropdown toggle button for "Shop").

Expected:

<button ... aria-label="Toggle Shop">

Actual:
<button ... aria-label="Toggle &lt;span class=\&quot;menu-item-title-wrap dd-title\&quot;&gt;Shop&lt;/span&gt;">

Root cause:

nav_walker.php:154:
$toggle_aria_label = __( 'Toggle', 'neve' ) . ' ' . wp_filter_nohtml_kses( $title );

$title at this point already contains our own ... wrapper (added a few lines earlier). We rely on wp_filter_nohtml_kses() to strip it back down to plain text before using it as an attribute value.

wp_filter_nohtml_kses() is a core WP function whose own docblock says "This function expects slashed data" — it's designed for sanitizing raw form/DB-bound input, not for stripping tags out of HTML we built ourselves. Internally it calls wp_kses( $data, 'strip' ), and that 'strip' context is passed through the public, pluggable wp_kses_allowed_html filter. Any plugin that hooks that filter and adds tags without checking $context === 'strip' will cause tags to survive a call that's supposed to guarantee zero tags. (Confirmed: Booster for WooCommerce's wcj_add_allowed_html() does exactly this.)

The value does get passed through esc_attr() before being output, so this isn't an XSS/broken-HTML issue — but it's a real accessibility regression (screen readers announce raw markup instead of the menu label) and is visible to anyone inspecting the DOM or running an accessibility audit.

Suggested fix:

Use wp_strip_all_tags() instead, since it does a plain string-based tag strip and never touches the wp_kses_allowed_html filter chain:
$toggle_aria_label = __( 'Toggle', 'neve' ) . ' ' . wp_strip_all_tags( $title );
This makes the dropdown toggle immune to this entire class of third-party filter conflicts, regardless of what any given plugin does wrong.

Severity: Low visual/security impact (escaped output), but a real accessibility bug and a support-burden source, since it presents as "menu looks broken" reports that are hard for less technical users/reporters to diagnose as a plugin conflict.

https://secure.helpscout.net/conversation/3451611756/496779

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.