← Back to Feed CACHED · 2026-10-30 18:29:43 · CACHE_KEY CVE-2026-92541
CVE-2026-92541 · CWE-269 · Disclosed 2026-09-20

WordPress users-customers import-export front-end missing promote_users check

ASSESSED — NOISGATE
Vendor
—
—
—
Reassessed
—
—
—
Verdict: —
Do you agree?
01 · The Real Story

A coat-check clerk who can rename any guest as the club owner on the front entrance list

The Import and export users and customers WordPress plugin before 2.5.2 lets an authenticated user with create_users but not promote_users submit a user import through the front-end that rewrites the role of an existing account. If the imported row sets role to administrator, the plugin updates that user's role without checking whether the importer can promote, so a Shop Manager (or any custom role with create_users) can escalate to full site admin.

Vendor severity HIGH/7.2 is measured accurately for the intended WooCommerce/membership deployment: create_users is a high-privilege capability but not by itself a path to admin, and the import endpoint is only reachable if an admin opted into front-end import. The result is a classic vertical privilege escalation with meaningful preconditions, so HIGH is appropriate—not CRITICAL because it is not unauth or low-priv, and not MEDIUM because successful exploitation grants full site takeover.

"A half-privileged shop manager can import themselves into the administrator role on sites using this plugin."
02 · The Attack Path

6 steps from start to impact.

STEP 01

Obtain an account with create_users but not promote_users

The attacker needs valid credentials or a session for a role such as WooCommerce Shop Manager. No public weaponized tool is required—standard HTTP requests via curl or a browser are sufficient to operate the plugin's front-end import feature.
Conditions required:
  • A WordPress role exists with create_users but lacking promote_users
  • Attacker has valid credentials or a stolen session for that role
Where this breaks in practice:
  • Default WordPress roles do not grant create_users to non-administrators; custom/e-commerce roles are required
  • Account takeover of a Shop Manager typically requires credential theft, phishing, or insider action
Detection/coverage: Review user role assignments for non-admin create_users; WordPress audit logs can show account logins
STEP 02

Locate the front-end import page or AJAX endpoint

The plugin exposes a front-end import function via a shortcode/page or admin-ajax.php action intended for customer/user import. The attacker browses to the import form and confirms it accepts a CSV upload.
Conditions required:
  • Site administrator enabled front-end import via shortcode or page
  • The vulnerable plugin version is installed and active
Where this breaks in practice:
  • Many deployments keep imports confined to wp-admin, limiting front-end reachable population
  • The import form may be hidden behind membership/login requirements beyond the already-authenticated session
Detection/coverage: WAF or web server logs may show requests to the import AJAX action or page; grep for plugin-specific action names
STEP 03

Submit a CSV import with an administrator role assignment

The attacker crafts a CSV import row containing an existing user's email or username and sets the role column to administrator. The plugin processes the role update without invoking current_user_can('promote_users'), so the change is accepted.
Conditions required:
  • Import function accepts a role field for existing users
  • CSV format matches plugin expectations
  • Target user exists
Where this breaks in practice:
  • The attacker must know a valid existing user identifier
  • Some hardened deployments may disable role editing through import or validate columns, though the vulnerability means the check is missing
Detection/coverage: Audit plugin import logs if enabled; security plugins that monitor wp_usermeta / user roles may catch the change
STEP 04

WordPress updates the target user's role to administrator

The database record for the target user is modified to assign the administrator role. The attacker does not need the target user's password at this stage; the role change is immediate and persistent.
Conditions required:
  • WordPress stores role in usermeta or user_level
  • No secondary authorization layer blocks the role transition
Where this breaks in practice:
  • If the target user has a different primary role cached, it may require re-login to reflect, but promotion is generally instant
Detection/coverage: File/DB integrity monitoring, WP activity log plugins, and SIEM can alert on unexpected administrator role assignments
STEP 05

Log in as the promoted user and gain full admin control

The attacker authenticates as the promoted user (or resets the password via admin if they control the email). Once inside as an administrator, they can install malicious plugins, edit theme files, or create new admin accounts.
Conditions required:
  • Attacker can authenticate as the promoted user (password reset, email access, or session takeover)
  • WordPress admin panel accessible
Where this breaks in practice:
  • Two-factor authentication on the target user could block login, but many accounts lack 2FA
  • Hardening that disables plugin/theme editor may slow post-exploit code execution, though admin can still exfiltrate data
Detection/coverage: Login monitoring, 2FA, admin session auditing, and EDR on the server for unexpected PHP process creation
STEP 06

Full site takeover and server code execution

With administrator rights, the attacker typically installs a malicious plugin or edits a theme PHP file to execute arbitrary code on the server. On WooCommerce/membership sites, this leads to mass customer data egress, defacement, or pivoting to other sites on shared hosting.
Conditions required:
  • WordPress file editing / plugin installation is allowed
  • Server permits PHP execution of modified files
Where this breaks in practice:
  • Hardened WordPress installations may disable file editor and plugin install, but admin can often re-enable via database if unfiltered_html or manage_options is present
  • EDR/application allowlisting on the server may catch web shells, but many WordPress hosts lack this
Detection/coverage: File integrity monitoring, server EDR, outbound data loss prevention, and unexpected admin activity alerts
03 · Compensating Control

1
HIGH 7.0→IGNORE 0.0
SEVERITY REDUCED
Update the plugin to 2.5.2 or latest — Installing the fixed release enforces promote_users in front-end import, eliminating the privilege escalation. Apply within 30 days (noisgate mitigation SLA for HIGH) and complete patching within 180 days (noisgate remediation SLA for HIGH).
2
HIGH 7.0→LOW 2.0
SEVERITY REDUCED
Remove or unpublish any front-end import page/shortcode — If you rely only on backend admin import, delete the public/authenticated front-end import form or restrict it to users holding both create_users and promote_users. This cuts off the vulnerable path immediately.
3
HIGH 7.0→MEDIUM 4.0
SEVERITY REDUCED
Remove create_users from all non-administrator roles — Review roles (WooCommerce Shop Manager, custom roles) and ensure only Administrators hold create_users. This removes the precondition for the exploit while retaining normal site operation for most stores.
4
HIGH 7.0→HIGH 7.0
Enable logging and alerting for user role changes — Detect any transition to administrator by non-admin import using WP audit log plugins or SIEM. This does not stop the exploit but reduces time to detect and respond.
What doesn't work
  • Two-factor authentication alone: an attacker with a valid session or cookie can call the import endpoint without re-authenticating.
  • A WAF rule blocking CSV uploads: the import is a legitimate authenticated feature, so blocks may be bypassed or harm business flow.
  • Disabling admin-ajax.php: the import may be served on a front-end page, and disabling AJAX breaks much of WordPress functionality.
04 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo active exploitation reported; not in CISA KEV as of assessment.
Proof-of-concept availabilityNo public PoC or exploit module found in PocIndex/GitHub for CVE-2026-92541; exploitation requires a custom CSV import via standard HTTP requests.
EPSS score0.00462 (0.462% probability of exploitation in next 30 days); percentile not disclosed.
KEV statusNot listed in CISA Known Exploited Vulnerabilities Catalog.
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H — high-privilege network attack, no user interaction, scope unchanged.
Affected versionsPlugin versions < 2.5.2.
Fixed version2.5.2
Scanning/exposure dataNo public internet-wide scan data (GreyNoise/Shodan/Censys) for this WordPress plugin; exposure is self-hosted and opt-in.
Disclosure date2026-09-20
Reporting researcher/orgNot disclosed in official CVE record.

Sources.

  1. CVE.org record CVE-2026-92541
  2. NVD detail CVE-2026-92541
  3. WordPress plugin page — Import Export WordPress Users and WooCommerce Customers
  4. Wordfence Threat Intelligence database
  5. Patchstack WordPress vulnerability database
  6. FIRST EPSS model
  7. CISA Known Exploited Vulnerabilities Catalog
  8. GitHub Advisory Database query for CVE-2026-92541
05 · The Call

Final Verdict
= UNCHANGED to HIGH (7.0/10)

Why this verdict

  • Friction audit: The attacker must already hold a create_users capability, which is a high-privilege capability typically assigned to Shop Manager or custom roles on WooCommerce/membership sites; default WordPress roles do not grant it to non-admins. This narrows the exposed population to sites that deliberately create lower-privileged user-import roles.
  • Front-end exposure: The vulnerable import must be enabled on a public page or AJAX endpoint; many administrators keep imports confined to wp-admin, adding a deployment-specific prerequisite.
  • Role multiplier: On WooCommerce/membership sites where Shop Manager is a standard role and this plugin is installed, successful promotion to administrator yields plugin/theme editing, code execution, and mass customer data egress; that high-value outcome plausibly represents ≥1% of the plugin's install base, flooring the verdict at HIGH.
  • Baseline: The vendor CVSS 7.2 (PR:H) already accounts for the elevated starting privileges; after friction and role analysis, a mild downgrade to 7.0 reflects the default-role non-exposure while preserving the HIGH floor.

Why not higher?

Not CRITICAL because the attacker must already possess a high-privilege capability and the vulnerable front-end import is opt-in; default WordPress installs without custom user-import roles are unaffected. There is no evidence of in-the-wild exploitation, KEV listing, or public PoC. The pre-auth network blast radius is zero, so the 9.0+ critical class does not apply.

Why not lower?

Friction cannot pull the verdict below HIGH because on the plugin's core use case (WooCommerce/membership stores with Shop Manager) a successful chain gives full administrative control and potential mass data egress. The promote_users gap is exactly the kind of vertical privilege escalation that turns a semi-trusted user into a site owner; residual risk after patching/detection is not enough to justify MEDIUM on the role-multiplier floor.

06 · Verification

Crowdsourced verification payload.

Run on the WordPress application host that serves the plugin files. Example: bash check_cve-2026-92541.sh /var/www/html (requires read access to wp-content/plugins). If run from within the WordPress root, omit the argument.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# CVE-2026-92541 check for WordPress Import and export users and customers < 2.5.2
set -euo pipefail

WP_ROOT="${1:-$(pwd)}"
VULN_PLUGIN_SLUGS=(
  'users-customers-import-export-for-wp-woocommerce'
  'import-export-users-and-customers'
  'import-export-users-customers'
)
FIXED_VERSION='2.5.2'

plugin_dir=''
for slug in "${VULN_PLUGIN_SLUGS[@]}"; do
  if [ -d "${WP_ROOT}/wp-content/plugins/${slug}" ]; then
    plugin_dir="${WP_ROOT}/wp-content/plugins/${slug}"
    break
  fi
done

if [ -z "$plugin_dir" ]; then
  echo "UNKNOWN: plugin directory not found under ${WP_ROOT}/wp-content/plugins"
  exit 0
fi

version_file="${plugin_dir}/$(basename "$plugin_dir").php"
[ -f "$version_file" ] || version_file=$(find "$plugin_dir" -maxdepth 1 -name '*.php' | head -n1)

version=$(grep -m1 '^ \* Version:' "$version_file" 2>/dev/null | awk '{print $NF}' || true)
[ -n "$version" ] || version=$(grep -m1 '^Version:' "$version_file" 2>/dev/null | awk '{print $2}' || true)

if [ -z "$version" ]; then
  echo "UNKNOWN: could not parse plugin version from $version_file"
  exit 0
fi

if [ "$(printf '%s\n%s\n' "$version" "$FIXED_VERSION" | sort -V | head -n1)" = "$version" ] && [ "$version" != "$FIXED_VERSION" ]; then
  echo "VULNERABLE: found plugin version ${version}, fixed version ${FIXED_VERSION}"
  exit 2
else
  echo "PATCHED: found plugin version ${version}"
  exit 0
fi