CVE-2021-24295 vulnerability and BitFire protection

How BitFire Blocks CVE-2021-24295: CleanTalk Anti-Spam SQL Injection

WordPress vulnerability research

BitFire's FREE WAF detects and blocks the unauthenticated SQL injection behind CVE-2021-24295 before the vulnerable CleanTalk code ever runs.

Unauthenticated CVSS 7.5 High Confidential database disclosure SQL Injection
BitFire · Vulnerability advisoryResearch published
AdvisoryCVE-2021-24295
ComponentAnti-Spam by CleanTalk – Spam Protection Without CAPTCHA
Relevant sourcelib/Cleantalk/ApbctWP/Firewall/SFW.php — SFW::update_log()
Executive summary

What WordPress administrators need to know

The SpamFireWall module in CleanTalk's Anti-Spam plugin runs in front of every WordPress page, and in versions through 5.153.3 its logging routine built SQL by string-concatenating the request's User-Agent header. CVE-2021-24295 (CVSS 7.5) lets any anonymous visitor turn that header into time-based blind SQL injection and read data from the WordPress database using only cookies the server itself helps issue. BitFire's FREE WAF recognizes the injection signature in the request and blocks it before WordPress loads the vulnerable code, cutting off the exploit at delivery. Version 5.153.4 parameterizes the query; BitFire Threat Hunter then sweeps previously exposed sites for attacker persistence.

At a glance

Key facts

  • Unauthenticated time-based blind SQL injection (CVE-2021-24295, CVSS 7.5) in the SpamFireWall logging routine.
  • Reachable from any front-end GET request when the spam_firewall setting is enabled — no login required.
  • User-Agent header concatenated into the firewall log SQL after HTML-only sanitization, never SQL-escaped.
  • Trigger requires a server-issued ct_sfw_pass_key cookie plus any non-empty ct_sfw_passed cookie.
  • Fixed in 5.153.4: both ua_name values are parameterized through $wpdb->prepare.
  • BitFire FREE WAF matches the injection signature in the request and blocks it before SFW::update_log() runs.
01
Vulnerability overview

Understand the exposure

The affected component, attack path, and practical risk for WordPress websites.

Affected componentAnti-Spam by CleanTalk – Spam Protection Without CAPTCHA
Potential reach200000 installations
Attack techniquetime-based blind sql injection
Published2026-10-02
BitFire's WAF shuts down CVE-2021-24295 at the request layer — the injected SQL in the User-Agent never reaches SFW::update_log(), so an anonymous attacker never gets a timing channel into your database.
02
Technical analysis

How the vulnerability works

Research details, affected versions, exploitation behavior, and remediation guidance.

An Anonymous SQL Injection on Every Front-End Request

CleanTalk's SpamFireWall initializes on non-admin GET requests whenever the spam_firewall setting is enabled. A visitor who passes the check receives a ct_sfw_pass_key cookie, and replaying it with any non-empty ct_sfw_passed cookie forces SFW::check() to call update_log() on that request. In 5.153.3 and earlier, update_log() interpolated the raw User-Agent header into an INSERT ... ON DUPLICATE KEY UPDATE statement after only HTML-oriented sanitization — sanitize_text_field and htmlspecialchars — neither of which escapes SQL quotes. The finished string went straight to $wpdb->query, so header content could restructure the statement. The result is CVE-2021-24295 (CVSS 7.5): unauthenticated time-based blind SQL injection that lets an attacker infer and extract confidential database contents through response timing, with no login and no user interaction.

BitFire FREE WAF: Blocked Before WordPress Runs

This vulnerability lives entirely in the request: the payload is inbound request data and must carry SQL syntax to break out of the ua_name value. That is precisely the boundary BitFire's FREE web application firewall defends. The WAF inspects requests for SQL injection signatures and common evasion patterns, and blocks matching requests before WordPress or any plugin processes them. With BitFire enabled, the crafted User-Agent never reaches SFW::update_log(), the malicious statement is never assembled, and $wpdb->query never executes attacker SQL — the timing channel into your database never opens. The documented limitation is that the malicious SQL syntax must be present in inspected request data; this exploit cannot avoid that requirement, because its payload is the injection itself.

If Your Site Was Affected, Investigate for Persistence

Update to CleanTalk 5.153.4 or later now. The patch replaces both interpolated ua_name values with %s placeholders prepared through $wpdb->prepare, so request data can no longer alter statement structure. Patching closes this known path, but it does not erase a past compromise: anyone who exploited the bug earlier could have read database contents — including user tables — and used that access to entrench. Run BitFire Threat Hunter (BitFire PRO) to sweep the site for backdoor WordPress administrator accounts, hidden database triggers, long-running PHP processes, and droppers that can reinstall malware after cleanup. If your site ever ran an affected version, patch immediately, investigate, remove every persistence mechanism found, and rotate your database and administrator credentials.

Stop the Injection at the Door with BitFire

CVE-2021-24295 proves that even logging code can hand anonymous attackers a channel into your database. BitFire FREE's WAF closes that channel at the request layer, blocking SQL injection signatures before the vulnerable code executes — protection that works today, without waiting for a vendor patch. Install BitFire, enable the web application firewall, update CleanTalk immediately, and if your site ever ran 5.153.3 or older, follow up with a BitFire PRO Threat Hunter investigation. Block the request. Keep the database yours.

03
Source review

Vulnerable and fixed code

The relevant source is located in lib/Cleantalk/ApbctWP/Firewall/SFW.php — SFW::update_log().

BeforeVulnerable behavior
$query = "INSERT INTO " . $this->db__table__logs . "
SET
    id = '$id',
    ip = '$ip',
    status = '$status',
    all_entries = 1,
    blocked_entries = " . ( strpos( $status, 'DENY' ) !== false ? 1 : 0 ) . ",
    entries_timestamp = '" . $time . "',
    ua_name = '" . sanitize_text_field( Server::get('HTTP_USER_AGENT') ) . "'
ON DUPLICATE KEY
UPDATE
    status = '$status',
    all_entries = all_entries + 1,
    blocked_entries = blocked_entries" . ( strpos( $status, 'DENY' ) !== false ? ' + 1' : '' ) . ",
    entries_timestamp = '" . intval( $time ) . "',
    ua_name = '" . sanitize_text_field( Server::get('HTTP_USER_AGENT') ) . "'";

$this->db->execute( $query );
AfterCorrected behavior
$query = "INSERT INTO " . $this->db__table__logs . "
SET
    id = '$id',
    ip = '$ip',
    status = '$status',
    all_entries = 1,
    blocked_entries = " . ( strpos( $status, 'DENY' ) !== false ? 1 : 0 ) . ",
    entries_timestamp = '" . $time . "',
    ua_name = %s
ON DUPLICATE KEY
UPDATE
    status = '$status',
    all_entries = all_entries + 1,
    blocked_entries = blocked_entries" . ( strpos( $status, 'DENY' ) !== false ? ' + 1' : '' ) . ",
    entries_timestamp = '" . intval( $time ) . "',
    ua_name = %s";

$this->db->prepare( $query, array( Server::get('HTTP_USER_AGENT'), Server::get('HTTP_USER_AGENT') ) );
$this->db->execute( $this->db->get_query() );
04
Zero-day protection

Protection from the first exploit request

BitFire protects WordPress servers on day zero—before a vulnerability is publicly known and before other vendors have time to develop signatures or patches.

01 · VerifyStop unknown clients

Bot controls and browser verification stop untrusted automated clients before previously unknown exploit code reaches WordPress.

02 · DetectBlock malicious behavior

General WAF protections identify dangerous request behavior and hostile payloads without waiting for a vulnerability-specific signature.

03 · PreventContain attacks at runtime

RASP follows execution inside PHP and prevents unauthorized changes to protected files, accounts, and database content.

BitFire · WordPress protectionZero-day ready
BitFire zero-day WordPress vulnerability protection
BitFire combines verified-client controls, behavior-based WAF detection, and runtime RASP enforcement to protect WordPress before an exploit has a name, CVE, signature, or vendor patch.
About the author

Cory Marsh

Cory has more than 20 years of internet security experience and is a lead developer on the BitFire project.

Read BitFire security research →
Protect your WordPress website

Add protection before the next exploit arrives.

BitFire combines bot controls, request inspection, malware detection, and runtime protection in one WordPress security platform.

Protect my site free →