This is a fake note slid under an admin’s office door, not a burglar kicking in the front gate
CVE-2025-22297 is a CSRF flaw in the WordPress plugin AI WP Writer affecting versions through 3.8.4.4, fixed in 3.8.4.5. Per WPScan, the root cause is missing or incorrect nonce validation in the plugin's options() function, which means a logged-in site administrator can be tricked into sending a forged request that changes plugin settings.
The vendor's MEDIUM 4.3 is technically fair in a vacuum, but for enterprise prioritization it still overstates the operational urgency. The exploit needs a live admin session and successful social engineering, the impact described publicly is limited to settings modification rather than code execution or credential theft, there is no KEV listing, and the plugin's public install base is only about 3,000 active sites on WordPress.org.
4 steps from start to impact.
Find a site using the plugin
ai-wp-writer, typically by plugin enumeration or routine WordPress fingerprinting. Public references show the plugin is active and distributed via WordPress.org, but there is no evidence of broad internet-scale exploitation or dedicated scanning for this CVE.- Target runs WordPress with the AI WP Writer plugin installed
- Attacker can identify or guess that the plugin is present
- Plugin-specific fingerprinting is weaker than for top-tier plugins
- The public install base is small relative to mainstream WordPress plugins
Lure an authenticated admin
- A site administrator is currently authenticated to
/wp-admin - The admin clicks a crafted link or loads attacker-controlled content
- Requires social engineering instead of direct remote reachability
- Admin sessions may be short-lived or isolated to separate browsers
- MFA does not help once the authenticated session already exists, but it does reduce casual admin reuse across devices
Abuse missing nonce validation in options()
options() allows unauthorized settings changes under the admin's existing privileges.- The vulnerable plugin version is
<= 3.8.4.4 - The request reaches the plugin settings handler in an authenticated admin context
- This is not an unauthenticated server-side exploit path
- The public description supports settings modification, not arbitrary file write or RCE
wp_options around admin browsing activity.Change plugin behavior, not the whole server
- The site materially depends on AI WP Writer settings
- Changed settings are not immediately noticed and reverted
- Blast radius is constrained to what the plugin settings actually control
- Operational staff may quickly notice content or configuration drift
/wp-admin behind VPN, allowlists, or SSO with conditional access where possible. That does not fix CSRF by itself, but it reduces the pool of admins who can be actively targeted; for a LOW verdict, do this during normal hardening work because there is no fixed noisgate mitigation SLA.wp_options entries. For a LOW issue, deploy this in the next scheduled monitoring improvement cycle if you cannot patch immediately.- A generic perimeter WAF alone does not solve this, because the forged request rides a legitimate authenticated admin session and may look normal to the server.
- Host EDR is usually not the answer here; the exploit is a browser-driven web request, not malware dropping on the server.
- MFA by itself does not block CSRF once the administrator already has an active session cookie.
The supporting signals.
| In-the-wild status | No public evidence of active exploitation found in the sources reviewed; OpenCVE shows KEV: no and CISA's KEV catalog does not list this CVE. |
|---|---|
| Proof-of-concept availability | No public GitHub exploit repo surfaced in primary search results. The exploit path is simple enough to reproduce with a basic forged HTML request, but there is no sign of mature weaponization. |
| EPSS | 0.00125 from the user-provided intel block, which is consistent with a low-likelihood, low-priority exploitation profile for a CSRF admin-click bug. |
| KEV status | Not KEV-listed as of the reviewed CISA catalog, and OpenCVE also marks it KEV no. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N — the key limiter is UI:R. No confidentiality impact, no availability impact, and only low integrity impact are exactly why this does not deserve urgent patch treatment. |
| Affected versions | AI WP Writer through 3.8.4.4 is affected. The CVE record and Wordfence both describe the vulnerable range as <= 3.8.4.4. |
| Fixed version | 3.8.4.5 is the first fixed release per the CVE CNA record and WPScan. Current WordPress.org version is much newer (4.5.8.3 at review time), so routine upgrades also clear this issue. |
| Exposure / scanning | Public scan engines do not reliably fingerprint this plugin from the open internet. The best population proxy here is WordPress.org's 3,000+ active installs and Wordfence's recorded 95,823 downloads, which points to a small-to-moderate niche plugin footprint, not a mass-enterprise exposure event. |
| Disclosure timeline | CVE was published on 2025-01-07 in the Patchstack-assigned CNA record; WPScan lists public publication on 2025-01-06 and Wordfence lists the vulnerability on January 6, 2025. |
| Researcher / reporter | The issue is attributed to Dhabaleshwar Das; the CVE was assigned by Patchstack and tracked by WPScan and Wordfence. |
Sources.
Why this verdict
- Baseline down: vendor scored it 4.3/MEDIUM, but that assumes the integrity impact matters more than the access path friction
- Major friction: exploitation requires a logged-in administrator plus a successful lure/click, which implies post-targeting and user interaction rather than direct remote abuse
- Population is narrow: WordPress.org shows roughly 3,000 active installs, so even among WordPress shops this is not a mass-footprint plugin
- Blast radius is limited: the public description supports plugin settings changes, not code execution, arbitrary file write, or full site takeover
- No threat signal: not in KEV, no public active exploitation evidence found, and the provided EPSS is very low
Why not higher?
There is no unauthenticated server-side path here. An attacker does not get to hit the target cold from the internet; they need the admin to be logged in and to cooperate by action, and even then the described impact is limited to settings manipulation.
Why not lower?
This is still a real integrity flaw, not paperwork. On sites that actively use the plugin, forged settings changes can alter publishing behavior or create spam/SEO cleanup work, and the attack primitive is simple once the attacker has an engaged admin target.
Crowdsourced verification payload.
Run this on the target WordPress host with read access to the plugin directory. Invoke it as bash check-ai-wp-writer-cve-2025-22297.sh /var/www/html or point it directly at the plugin directory root; no root privileges are required unless your web files are permission-restricted.
#!/usr/bin/env bash
# check-ai-wp-writer-cve-2025-22297.sh
# Detect AI WP Writer versions affected by CVE-2025-22297.
# Output: VULNERABLE / PATCHED / UNKNOWN
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN, 3=usage error
set -u
FIXED_VERSION="3.8.4.5"
TARGET_PATH="${1:-}"
PLUGIN_SLUG="ai-wp-writer"
usage() {
echo "Usage: $0 <wordpress_root_or_plugin_dir>"
exit 3
}
if [[ -z "$TARGET_PATH" ]]; then
usage
fi
if [[ ! -e "$TARGET_PATH" ]]; then
echo "UNKNOWN - path does not exist: $TARGET_PATH"
exit 2
fi
# Resolve plugin dir whether caller passed WP root or plugin dir
PLUGIN_DIR=""
if [[ -d "$TARGET_PATH/wp-content/plugins/$PLUGIN_SLUG" ]]; then
PLUGIN_DIR="$TARGET_PATH/wp-content/plugins/$PLUGIN_SLUG"
elif [[ -d "$TARGET_PATH/$PLUGIN_SLUG" ]]; then
PLUGIN_DIR="$TARGET_PATH/$PLUGIN_SLUG"
elif [[ -d "$TARGET_PATH" && "$(basename "$TARGET_PATH")" == "$PLUGIN_SLUG" ]]; then
PLUGIN_DIR="$TARGET_PATH"
else
echo "UNKNOWN - could not locate plugin directory for $PLUGIN_SLUG under: $TARGET_PATH"
exit 2
fi
verlte() {
# returns success if $1 <= $2
[[ "$1" == "$2" ]] && return 0
local first
first=$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)
[[ "$first" == "$1" ]]
}
extract_version_from_file() {
local file="$1"
local ver
ver=$(grep -Eim1 '^[[:space:]]*Version:[[:space:]]*' "$file" 2>/dev/null | sed -E 's/^[[:space:]]*Version:[[:space:]]*//I' | tr -d '\r')
if [[ -n "$ver" ]]; then
echo "$ver"
return 0
fi
return 1
}
VERSION=""
SOURCE_FILE=""
# Prefer readme.txt if present
if [[ -f "$PLUGIN_DIR/readme.txt" ]]; then
VERSION=$(extract_version_from_file "$PLUGIN_DIR/readme.txt" || true)
if [[ -n "$VERSION" ]]; then
SOURCE_FILE="$PLUGIN_DIR/readme.txt"
fi
fi
# Fall back to plugin PHP headers
if [[ -z "$VERSION" ]]; then
while IFS= read -r -d '' phpfile; do
VERSION=$(extract_version_from_file "$phpfile" || true)
if [[ -n "$VERSION" ]]; then
SOURCE_FILE="$phpfile"
break
fi
done < <(find "$PLUGIN_DIR" -maxdepth 2 -type f -name '*.php' -print0 2>/dev/null)
fi
if [[ -z "$VERSION" ]]; then
echo "UNKNOWN - could not extract plugin version from $PLUGIN_DIR"
exit 2
fi
if verlte "$VERSION" "$FIXED_VERSION" && [[ "$VERSION" != "$FIXED_VERSION" ]]; then
echo "VULNERABLE - AI WP Writer version $VERSION detected in $SOURCE_FILE (fixed in $FIXED_VERSION)"
exit 1
elif [[ "$VERSION" == "$FIXED_VERSION" ]]; then
echo "PATCHED - AI WP Writer version $VERSION detected in $SOURCE_FILE"
exit 0
else
echo "PATCHED - AI WP Writer version $VERSION detected in $SOURCE_FILE"
exit 0
fi