| Plugin Name | Allow HTML in Category Descriptions |
|---|---|
| Type of Vulnerability | Cross-Site Scripting (XSS) |
| CVE Number | CVE-2026-0693 |
| Urgency | Low |
| CVE Publish Date | 2026-02-13 |
| Source URL | CVE-2026-0693 |
Urgent: Stored XSS in “Allow HTML in Category Descriptions” (<= 1.2.4) — What WordPress Site Owners Must Do Now
Summary: A stored Cross-Site Scripting (XSS) vulnerability (CVE-2026-0693) has been disclosed in the WordPress plugin “Allow HTML in Category Descriptions” (versions ≤ 1.2.4). An authenticated user with Administrator-level privileges can inject malicious HTML/JavaScript into category descriptions that can later execute in visitors’ or other administrators’ browsers. There is currently no official patch for the vulnerable versions. This advisory explains technical details, threat scenarios, immediate mitigations, detection and clean-up steps, and longer-term hardening from the perspective of a Hong Kong security expert.
Note: If you run this plugin and have an affected version installed, treat this as a high-priority site security task — even though the vulnerability requires administrator privileges, the impact can be significant in practice.
What is the vulnerability?
- Type: Stored Cross-Site Scripting (XSS).
- Affected component: WordPress plugin “Allow HTML in Category Descriptions” — versions ≤ 1.2.4.
- CVE: CVE-2026-0693.
- CVSS: 5.9 (medium), Vector: CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:L.
- Root cause: The plugin allows administrators to save unfiltered HTML in taxonomy descriptions without proper sanitization or output encoding. Malicious JavaScript stored in a category description can be executed in the context of a page that renders that description (front-end or certain admin views), enabling cookie theft, privilege abuse, or actions performed with the victim’s browser session.
Why this matters: Administrators are trusted accounts. An attacker who compromises an admin account (or tricks an admin to save a crafted description) can persist scripts that victimize other admin users or site visitors. Consequences include site defacement, credential harvesting, malicious redirects, or full site takeover through chained attacks.
How an attacker can exploit this
- Attacker obtains or compromises an Administrator account (phishing, password reuse, insider), or tricks an admin into saving a payload.
- Through the plugin interface (category edit screen) or another entry point that updates taxonomy descriptions, the attacker injects a payload into the category description field — e.g., <script>…</script>, an SVG with an onload/onerror handler, or attribute-based payloads such as onmouseover, srcset, or javascript: URIs.
- The payload is stored in the database (term_taxonomy.description).
- When an admin or visitor views the category page (or any admin page rendering that description), the script runs in their browser within the site’s origin.
- Possible attacker actions include:
- Collect cookies/localStorage and send them to a remote server.
- Use the victim’s authenticated browser session to call WordPress REST/AJAX endpoints (potentially creating users, installing plugins, modifying options) if nonce or capability checks are weak.
- Inject further malicious content (ads, redirects, credential harvesting forms) or modify admin pages.
Important nuance: Many WordPress installations set auth cookies as HttpOnly, preventing direct cookie access by JS. However, JavaScript can still perform authenticated XHR/fetch requests if same-origin and nonce protections are absent or if nonces are stolen. Attackers can chain XSS with other weaknesses to escalate impact.
User interaction: Although some reports classify this as requiring user interaction (e.g., an admin visiting a crafted page), stored XSS is persistent and can execute automatically when pages are loaded.
Immediate, prioritized actions (within the next hour)
- Disable the plugin now
Go to wp-admin → Plugins and deactivate “Allow HTML in Category Descriptions” immediately. If you cannot access the admin panel, disable via FTP or hosting file manager by renaming the plugin folder:
wp-content/plugins/allow-html-in-category-descriptions→ append-disabled. - Put the site in maintenance mode (if appropriate)
If you suspect active exploitation (visible redirects, defacement, spam), temporarily block public access while you investigate.
- Audit and rotate administrative credentials
Force password resets for all Administrator accounts. Revoke sessions and tokens (Users → All Users → for each admin, “Log out everywhere” or use session-expiry tools). Enforce strong passwords and enable Two-Factor Authentication (2FA) for admin accounts.
- Block new requests that attempt to save XSS payloads
If you can deploy request filtering at the host, CDN, or via a Web Application Firewall (WAF), block POST requests that attempt to save category descriptions containing script-like patterns. See suggested WAF rules later in this article.
- Backup your site (files + DB)
Create a full backup before modifying or cleaning the site. Export the database and download wp-content and uploads for forensic copies.
- Scan for indicators of compromise immediately
Look for unexpected users, unknown files, scheduled tasks (wp_cron jobs), changed option values, and injected content in posts, pages, and taxonomy descriptions.
Investigation: find malicious category descriptions and scope the damage
Category descriptions are stored in the database; search for script-like content quickly.
Using WP-CLI (recommended if you have shell access):
wp db query "SELECT term_taxonomy_id, term_id, description FROM wp_term_taxonomy WHERE description LIKE '%<script%';"
wp db query "SELECT term_taxonomy_id, term_id, description FROM wp_term_taxonomy WHERE description REGEXP '(script|onerror|onload|javascript:|data:|iframe|svg|img)';"
If you don’t have WP-CLI, run equivalent SQL in phpMyAdmin or your hosting database tool.
Also check:
- Posts and pages: search
post_contentfor similar patterns:SELECT ID, post_title FROM wp_posts WHERE post_content REGEXP '(<script|onerror|onload|javascript:)'; - Widgets and theme options: check
wp_optionsfor injected HTML. - Plugin/theme files for unfamiliar or obfuscated code.
If you find suspicious descriptions, export them for forensics before making mass modifications.
Cleaning infected descriptions safely
Option A — Manual removal (small number of entries)
Use wp-admin → Posts/Terms editor and manually edit descriptions to remove payloads: Posts → Categories → edit each suspect category description.
Option B — Database cleanup (large or automated cleanup)
Test on a backup first. Example SQL to remove <script> blocks:
-- Remove <script>...</script> blocks from term descriptions
UPDATE wp_term_taxonomy
SET description = REGEXP_REPLACE(description, '<script[^>]*>.*?</script>', '', 'si')
WHERE description REGEXP '<script[^>]*>';
Stripping event handler attributes like onload/onerror is more complex; prefer a PHP-based sanitizer to avoid breaking legitimate markup.
Option C — Sanitize through a PHP script using WordPress functions (safer)
Create a one-off PHP script and run via WP-CLI eval-file or an admin-only execution path:
<?php
// sanitize-term-descriptions.php
require_once 'wp-load.php';
$terms = get_terms( array(
'taxonomy' => 'category',
'hide_empty' => false,
) );
$allowed_tags = array(
'a' => array('href' => true, 'title' => true, 'rel' => true, 'target' => true),
'b' => array(),
'strong' => array(),
'i' => array(),
'em' => array(),
'p' => array(),
'br' => array(),
'ul' => array(),
'ol' => array(),
'li' => array(),
'span' => array('class' => true),
// add only tags/attributes you trust
);
foreach ( $terms as $term ) {
$clean = wp_kses( $term->description, $allowed_tags );
if ( $clean !== $term->description ) {
wp_update_term( $term->term_id, 'category', array('description' => $clean) );
echo "Cleaned term {$term->term_id}
";
}
}
?>
Run with:
wp eval-file sanitize-term-descriptions.php
Notes: Using wp_kses with a minimal allowlist is safer than regex-only approaches. Test on a staging site or backup first.
Suggested defensive WAF rules and short-term virtual patching
If you have the ability to configure a WAF, CDN rules, or host request filtering, add rules to block attempts to store suspicious payloads or to block rendering of known-suspicious content. These measures are temporary mitigations while you remove the vulnerable plugin or fully remediate the site.
Simple detection heuristics
- Block POST requests to
/wp-admin/term.phpor REST endpoints used to save term descriptions that contain<script,onerror=,onload=,javascript:,data:text/html,svg/onload,iframe, or suspicioussrcattributes withdata:/javascript:. - Block requests that include
<svgwith event handlers, orstyle="background:url(javascript:style injections.
Example ModSecurity-style rule (pseudocode — tune for your environment):
# Block attempts to save category descriptions containing <script> or event handlers
SecRule REQUEST_METHOD "POST" "chain,phase:2,deny,log,msg:'Block term description XSS attempt'"
SecRule REQUEST_URI "@contains /wp-admin/term.php" "chain"
SecRule ARGS_POST:description "@rx (<script|onerror|onload|javascript:|data:|iframe|svg|img\s+[^>]*on)" "t:none,t:lowercase"
For REST endpoints (if the plugin exposes REST or uses admin-ajax):
# Block suspicious payloads in REST requests
SecRule REQUEST_BODY "@rx (<script|onerror|onload|javascript:|data:|iframe|svg)" "deny,log,msg:'Block REST XSS payload'"
Important: WAF rules are a stop-gap. They reduce risk while you remove the plugin or patch the site, but they do not replace removing vulnerable code or thorough cleanup.
Detection: what to look for after cleanup
- Unexpected admin users or new accounts with elevated roles.
- Scheduled tasks that run unknown code (check
wp_optionscron entries and wp_cron). - Unexpected plugins or themes installed/changed (compare file checksums with repository versions).
- Suspicious outgoing connections and DNS lookups from your server.
- Requests in logs that reflect the payload pattern or include suspicious redirection or exfiltration endpoints.
- Unusual admin activity timestamps, IPs, or failed login attempts.
Useful WP-CLI commands:
# List administrators
wp user list --role=administrator
# Show recent cron events
wp cron event list --due-now
# Check plugin/theme checksums (if available)
wp plugin verify-checksums plugin-slug
Incident response & recovery checklist
- Quarantine the site (maintenance mode or temporary block) if exploitation is suspected.
- Take full backups (files + DB) and preserve copies for forensic review.
- Disable the vulnerable plugin immediately.
- Sanitize database entries (term descriptions, posts, options).
- Rotate all admin passwords and API keys. Revoke and reissue any compromised tokens.
- Enable 2FA for all privileged accounts; limit admin accounts.
- Review and remove any backdoors (unexpected PHP files, base64/obfuscated code).
- Reinstall WordPress core, themes, and plugins from trusted sources if tampering is found.
- Restore from a known-good backup if the site integrity cannot be confidently restored.
- Monitor logs and site behavior closely for a period after remediation.
If you are not comfortable performing these steps yourself, engage a trusted WordPress security professional or incident response specialist.
Longer-term mitigation & hardening
- Principle of least privilege: Give Administrator role sparingly. Use Editor or custom roles for day-to-day content editing when possible.
- Limit untrusted HTML input: Avoid plugins that permit arbitrary HTML from privileged users. Where HTML is necessary, enforce strict sanitization using
wp_kseswith a small allowlist. - Keep plugins and themes to a minimum and only install from reputable sources. Regularly audit installed plugins and remove unused ones.
- Use version control and file integrity monitoring to detect unauthorized changes to theme and plugin files.
- Use secure authentication practices: 2FA, strong passwords, password managers, and account usage monitoring.
- Harden REST API and AJAX endpoints: Ensure nonce and capability checks on server-side handlers.
- Implement request filtering / WAF protection and continuous malware scanning with request body inspection to catch injected payloads in POST requests.
- Monitor vulnerability advisories for the plugins you use; subscribe to credible security mailing lists or advisories.
Sample PHP hardening snippet for theme or mu-plugin
If you want to prevent saving HTML to term descriptions at the WordPress application level (a temporary hardening if you cannot remove the plugin immediately), create a must-use plugin that strips unsafe tags on term creation/update.
Create wp-content/mu-plugins/sanitize-term-descriptions.php with the following content (edit allowed tags as needed):
<?php
/*
Plugin Name: Sanitize Term Descriptions - emergency
Description: Strip dangerous HTML from term descriptions as an emergency stopgap.
Author: Security Team
*/
add_action('created_term', 'sanitize_term_description_on_save', 10, 3);
add_action('edited_term', 'sanitize_term_description_on_save', 10, 3);
function sanitize_term_description_on_save($term_id, $tt_id = 0, $taxonomy = '') {
$term = get_term($term_id, $taxonomy);
if (!$term) {
return;
}
// Allow only minimal HTML
$allowed = array(
'a' => array('href' => true, 'title' => true, 'rel' => true, 'target' => true),
'br' => array(),
'p' => array(),
'b' => array(),
'strong' => array(),
'i' => array(),
'em' => array(),
);
$clean = wp_kses($term->description, $allowed);
if ($clean !== $term->description) {
wp_update_term($term_id, $taxonomy, array('description' => $clean));
}
}
This will proactively clean descriptions when terms are created or edited. It is an emergency measure — do not rely on it long-term if the plugin enables rich HTML editing.
Example detection signatures to monitor in logs
- Request bodies containing
<scriptorjavascript:in combination withwp-admin/term.php, REST endpoints, oradmin-ajax.php. - Admin POSTs that include
descriptionwith suspicious attributes (onerror=,onload=,data:). - Sudden increase of requests to taxonomy pages resulting in redirects or external calls to unknown domains.
- Creation or modification of terms at unusual hours or from uncommon IP addresses.
Real-world impact scenarios
- Scenario A: Script in a category description creates a new admin user via admin AJAX endpoints using the victim admin’s browser → full site takeover.
- Scenario B: Script loads external malicious JS and redirects visitors to adware or phishing landing pages → reputational and SEO damage.
- Scenario C: Script harvests form inputs or session information and exfiltrates to attacker domains → targeted follow-up attacks.
These outcomes are realistic even when the initial vector requires admin privileges — attackers commonly use social engineering and credential reuse to gain the necessary access.
Preventative development advice (for plugin/theme authors and agencies)
- Never trust user input — even from administrators. Always sanitize output using context-appropriate escaping (
esc_html,esc_attr,wp_kses_postwith a strict allowlist). - For editable HTML fields, persist only sanitized, validated HTML and store safe variants (or use a WYSIWYG that sanitizes on save).
- Implement capability and nonce checks on all server-side endpoints that modify site state (admin-ajax handlers, REST endpoints).
- Add automated unit/integration tests around XSS vectors and sanitize/escape flows in CI.
- Maintain a responsible disclosure channel and update policy so users receive timely fixes.
Quick recap & final checklist
- If you run “Allow HTML in Category Descriptions” (≤ 1.2.4): disable the plugin immediately.
- Backup site (files + DB) and take forensic copies.
- Scan and sanitize term descriptions (WP-CLI SQL queries or
wp_ksesPHP script). - Rotate admin passwords and enable 2FA. Revoke sessions and API tokens if in doubt.
- Deploy WAF/request-filtering to stop POSTs that try to save script-like payloads (virtual patch).
- Inspect for further compromise (new users, new files, changed options).
- Rebuild or restore from a known-clean backup if tampering is extensive.
- Replace the plugin with safer alternatives or restrict HTML to strictly sanitized content only.
If you need assistance with triage, WAF rule creation, rapid virtual patching, or a detailed remediation plan, engage a reputable security professional or incident response firm experienced with WordPress. Treat taxonomy fields that accept HTML as high-risk inputs — strict sanitization and output escaping are essential.
Advisory prepared by: Hong Kong Security Expert — concise, practical, and focused on rapid, evidence-based remediation.