← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
CVE-2021-24931 · CWE-89 · Disclosed 2021-12-06

The Secure Copy Content Protection and Content Locking WordPress plugin before 2

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
01 · The Real Story

This is a side door left unlocked on a storefront that only exists if you installed this exact plugin

CVE-2021-24931 is an unauthenticated SQL injection in the *Secure Copy Content Protection and Content Locking* WordPress plugin. Affected versions are all releases before 2.8.2; the bug sits in the ays_sccp_results_export_file AJAX action, where the sccp_id parameter is fed into a SQL query without proper sanitization. Because the action is reachable through /wp-admin/admin-ajax.php for unauthenticated users, an external attacker can hit it directly over HTTP and pull or tamper with WordPress database content.

The raw 9.8 score is directionally understandable on a lab bench: no auth, no user click, database compromise potential. In real fleets, though, this is not a universal WordPress bug; it only matters on sites running this specific plugin, and even then the practical target set is public-facing WordPress estates rather than your whole enterprise. That trims it down from *internet-on-fire critical* to a very solid HIGH—still patch-worthy fast because public PoC, scanner support, high EPSS, and current attack telemetry all keep the risk elevated.

"Unauthenticated SQLi on a public WordPress AJAX endpoint is dangerous, but the blast radius is capped by this plugin’s niche footprint."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Identify a site running the plugin

An attacker first fingerprints WordPress and checks whether secure-copy-content-protection is installed. Common tooling is WPScan, passive plugin enumeration, or a nuclei template reference set that specifically targets this CVE. Once the plugin is confirmed, the attacker knows a public AJAX route may be reachable without login.
Conditions required:
  • Target runs WordPress
  • The vulnerable plugin is installed in a version older than 2.8.2
  • The site is reachable over HTTP/HTTPS
Where this breaks in practice:
  • This is a plugin-specific flaw, not a WordPress core issue
  • Many enterprises do not run this plugin at all
  • Passive fingerprinting can fail if plugin paths are hidden or aggressively cached
Detection/coverage: Good coverage for version discovery in WordPress-focused scanners like *WPScan*; internet-wide fingerprinting is imperfect because plugins are not always banner-obvious.
STEP 02

Reach the unauthenticated AJAX handler

The exploit path uses /wp-admin/admin-ajax.php?action=ays_sccp_results_export_file. Because this action is exposed to unauthenticated users, the attacker does not need a WordPress account, session, or CSRF setup. Weaponization is simple with curl, browser requests, or sqlmap pointed at the vulnerable parameter.
Conditions required:
  • The site's admin-ajax.php endpoint is externally reachable
  • No upstream control blocks the request shape
Where this breaks in practice:
  • Some WAFs and managed WordPress front ends will flag obvious SQLi syntax
  • Rate limits or bot controls can slow bulk exploitation
Detection/coverage: HTTP-layer tools can see this. Look for unusual GET/POST requests to /wp-admin/admin-ajax.php with action=ays_sccp_results_export_file and malformed sccp_id values.
STEP 03

Exploit sccp_id with SQL injection

The sccp_id parameter is concatenated into a database query without safe preparation. Public references include a WPScan proof of concept and a ProjectDiscovery nuclei template that uses time-based SQLi for validation; operators can move from that to sqlmap for enumeration and extraction. In the common WordPress deployment model, the app's DB user has broad rights over the WordPress schema, so the attacker can often read user hashes, emails, and site configuration.
Conditions required:
  • Backend database executes the crafted payload
  • WordPress DB credentials used by the app have normal schema access
Where this breaks in practice:
  • Blind/time-based extraction is slower than a clean UNION path
  • Custom DB hardening or reduced grants can limit write impact
  • WAF normalization may break noisy payloads before they land
Detection/coverage: Strong candidate for WAF, reverse-proxy, and database audit alerts. Time-based probes often stand out through repeated delayed requests to the same AJAX action.
STEP 04

Turn database access into tenant compromise

With data extraction, the attacker can dump wp_users, steal password hashes, enumerate salts and options, or alter application data. Depending on DB permissions and local hardening, they may pivot into admin takeover by changing credentials or planting data that supports later code execution through the CMS. The practical impact is typically full compromise of that WordPress site and its content store, not broad domain-wide enterprise takeover.
Conditions required:
  • Useful data exists in the WordPress database
  • The attacker can successfully extract or modify rows
Where this breaks in practice:
  • Impact is mostly confined to the affected WordPress tenant
  • EDR does not help much until the attacker moves beyond SQLi into post-exploitation
  • Strong credential hygiene can blunt the value of dumped password hashes
Detection/coverage: Most vulnerability scanners stop at exposure detection. Deep impact confirmation usually requires database logs, WAF telemetry, or WordPress application logs.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusNot in CISA KEV, but this is not dormant. CrowdSec currently reports 636 exploiting IPs and steady automated scanning against the vulnerable AJAX route.
Proof-of-concept availabilityPublic PoC exists in the WPScan advisory. NVD also links a Packet Storm exploit reference, and ProjectDiscovery ships a nuclei template.
EPSS0.7216 with roughly 98.8th percentile exposure pressure, which is very high for a WordPress plugin CVE.
KEV statusAbsent from the CISA Known Exploited Vulnerabilities catalog at time of review.
CVSS vector reality checkCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H correctly captures the *technical* ease and impact, but it ignores the biggest real-world filter: only sites running this specific plugin are in play.
Affected versionsAll plugin versions before 2.8.2 are affected; NVD models this as a CPE range ending before 2.8.2.
Fixed versionsThe flaw is fixed in 2.8.2. The public plugin has since moved far beyond that; WordPress.org currently lists 5.1.6.
Exposure populationWordPress.org currently shows 20,000+ active installations. That is meaningful internet exposure, but still far smaller than a mainstream plugin or WordPress core issue.
Disclosure timelineWPScan lists public publication on 2021-11-08; NVD published the CVE on 2021-12-06.
Researcher / submitterCredited to Krzysztof Zając, per WPScan/OpenCVE record data.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to HIGH (8.8/10)

The decisive factor is that this is unauthenticated remote SQLi on a public endpoint, which keeps exploitation friction low once a target is found. It stays out of CRITICAL because the reachable population is materially narrowed by the requirement that the victim run this specific WordPress plugin, so this is a dangerous internet-facing application flaw rather than an all-fleet emergency.

HIGH Technical exploitability and affected version range
MEDIUM Observed exploitation pressure outside KEV based on third-party telemetry
HIGH Severity downgrade from NVD 9.8 to practitioner HIGH

Why this verdict

  • Unauthenticated remote path: no login, no click, no prior foothold; the attacker can hit admin-ajax.php directly from the internet, which preserves a high baseline.
  • Public weaponization exists: WPScan published a concrete PoC, NVD links exploit references, and ProjectDiscovery maintains a ready-made nuclei check. This is easy to operationalize with curl, sqlmap, or scanner automation.
  • Observed attack pressure is real: despite no KEV listing, CrowdSec reports active exploitation telemetry and hundreds of exploiting IPs, so this is not theoretical shelfware.
  • Downward pressure from exposure population: this is a plugin-specific bug. The attacker needs a site that actually runs *Secure Copy Content Protection and Content Locking* below 2.8.2, which sharply narrows the target fraction versus a core WordPress or mass-market plugin issue.
  • Blast radius is usually tenant-level: compromise is often severe for the affected WordPress site, but it does not inherently imply domain-wide enterprise compromise unless that site is already a privileged hub.

Why not higher?

I am not calling this CRITICAL because the main friction is population reachability, not exploit syntax. A 9.8 score assumes every network-reachable instance matters equally; in production, only a subset of public WordPress sites with this exact plugin installed are exposed, and the likely blast radius is usually one web tenant at a time rather than immediate estate-wide compromise.

Why not lower?

I am not dropping this to MEDIUM because the attack does not require credentials, internal access, user interaction, or chaining with another bug. Add the public PoC, scanner support, and active opportunistic exploitation telemetry, and this is well above backlog hygiene.

05 · Compensating Control

What to do — in priority order.

  1. Block the vulnerable AJAX action — At the reverse proxy or WAF, block requests to /wp-admin/admin-ajax.php where action=ays_sccp_results_export_file, or restrict that action to trusted admin source ranges if the workflow is genuinely needed. Because there is active exploitation evidence, deploy this within hours, not on a normal 30-day HIGH cycle.
  2. Pull external exposure on low-value sites — If the affected site does not need to be public, put it behind VPN, identity-aware proxy, or temporary maintenance controls. This sharply cuts attacker reach and should be done within hours for any internet-facing instance that cannot be patched immediately.
  3. Hunt for exploitation telemetry — Search WAF, reverse-proxy, and web logs for /wp-admin/admin-ajax.php requests with action=ays_sccp_results_export_file, array-style sccp_id[], UNION, SLEEP(, or abnormally repeated export attempts. Start the hunt immediately and keep it active until patch coverage is complete.
  4. Constrain database privileges where feasible — If your WordPress DB accounts are over-permissioned, reduce them to the minimum schema rights needed by the application. This will not prevent exploitation, but it can limit post-injection write impact; treat it as a supporting control and complete it within the normal HIGH remediation window if urgent containment is already in place.
  5. Patch the plugin everywhere it exists — Upgrade all instances to 2.8.2 or later and verify no stragglers remain in staging, DR, or forgotten marketing sites. Because current exploitation exists, treat patching as accelerated and begin within hours, not at the edge of the usual HIGH timeline.
What doesn't work
  • EDR on the web server does not reliably stop SQLi at the HTTP layer; it only helps if the intrusion turns into post-exploitation on the host.
  • Hiding wp-content/plugins/ paths is not a control. It may slow passive fingerprinting, but the vulnerable endpoint can still be probed directly.
  • MFA for WordPress admins is good hygiene but irrelevant to the initial exploit path, because this bug is reachable without authentication.
06 · Verification

Crowdsourced verification payload.

Run this on the target WordPress host or in a build/CI artifact where the plugin files are present. Invoke it as bash check-cve-2021-24931.sh /var/www/html and use a path to the WordPress root; read access only to the plugin directory is sufficient.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check-cve-2021-24931.sh
# Detects whether the Secure Copy Content Protection and Content Locking plugin
# is vulnerable to CVE-2021-24931 based on installed version.
#
# Usage: bash check-cve-2021-24931.sh /path/to/wordpress
# Exit codes:
#   0 = PATCHED
#   1 = VULNERABLE
#   2 = UNKNOWN (not installed / unreadable / cannot determine)

set -u

TARGET_VERSION="2.8.2"
WP_ROOT="${1:-}"
PLUGIN_DIR_REL="wp-content/plugins/secure-copy-content-protection"

if [[ -z "$WP_ROOT" ]]; then
  echo "UNKNOWN - usage: $0 /path/to/wordpress"
  exit 2
fi

PLUGIN_DIR="$WP_ROOT/$PLUGIN_DIR_REL"

if [[ ! -d "$PLUGIN_DIR" ]]; then
  echo "UNKNOWN - plugin directory not found: $PLUGIN_DIR"
  exit 2
fi

# Find the plugin header file by looking for the plugin name or a Version header.
PLUGIN_FILE=""
while IFS= read -r -d '' file; do
  if grep -qi "Plugin Name:.*Secure Copy Content Protection" "$file" 2>/dev/null; then
    PLUGIN_FILE="$file"
    break
  fi
done < <(find "$PLUGIN_DIR" -maxdepth 2 -type f -name '*.php' -print0 2>/dev/null)

if [[ -z "$PLUGIN_FILE" ]]; then
  # Fallback: grab the first PHP file with a Version header.
  while IFS= read -r -d '' file; do
    if grep -qi '^\s*Version:' "$file" 2>/dev/null; then
      PLUGIN_FILE="$file"
      break
    fi
  done < <(find "$PLUGIN_DIR" -maxdepth 2 -type f -name '*.php' -print0 2>/dev/null)
fi

if [[ -z "$PLUGIN_FILE" || ! -r "$PLUGIN_FILE" ]]; then
  echo "UNKNOWN - could not locate readable plugin header file"
  exit 2
fi

INSTALLED_VERSION=$(awk -F': *' 'BEGIN{IGNORECASE=1} /^\s*Version:/ {print $2; exit}' "$PLUGIN_FILE" | tr -d '\r')

if [[ -z "$INSTALLED_VERSION" ]]; then
  echo "UNKNOWN - could not parse version from $PLUGIN_FILE"
  exit 2
fi

version_lt() {
  # returns 0 if $1 < $2
  [[ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)" != "$2" && "$1" != "$2" ]]
}

if version_lt "$INSTALLED_VERSION" "$TARGET_VERSION"; then
  echo "VULNERABLE - installed version $INSTALLED_VERSION is older than fixed version $TARGET_VERSION"
  exit 1
fi

if [[ "$INSTALLED_VERSION" == "$TARGET_VERSION" || "$(printf '%s\n%s\n' "$INSTALLED_VERSION" "$TARGET_VERSION" | sort -V | tail -n1)" == "$INSTALLED_VERSION" ]]; then
  echo "PATCHED - installed version $INSTALLED_VERSION is at or above fixed version $TARGET_VERSION"
  exit 0
fi

echo "UNKNOWN - installed version $INSTALLED_VERSION could not be compared reliably"
exit 2
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning plan: inventory every WordPress instance for the secure-copy-content-protection plugin, assume any internet-facing host below 2.8.2 is exposed, and put a temporary block on the vulnerable AJAX action immediately, within hours because there is live exploitation telemetry. Even though the reassessed bucket is HIGH, active exploitation overrides the normal timetable: for this case, treat the noisgate mitigation SLA as patch / mitigate immediately, within hours, then complete the actual plugin upgrade under the noisgate remediation SLA well before 180 days—realistically this should be finished in the current patch cycle, not left to long-tail backlog.

Sources

  1. NVD CVE-2021-24931
  2. WPScan advisory
  3. WordPress.org plugin page and changelog
  4. OpenCVE record with credit and metadata
  5. CISA Known Exploited Vulnerabilities catalog
  6. CrowdSec CVE explorer telemetry
  7. ProjectDiscovery nuclei template
  8. Tenable CVE page
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.