How Nested POST Keys Become Admin-Facing Script
Zero Spam hooks Contact Form 7's wpcf7_validate filter and passes the entire $_POST array through Utilities::sanitize_array(). That function sanitizes values only — never keys. PHP turns bracket-syntax field names into nested array keys, so script markup hidden in a key name survives sanitization untouched. The path is reachable wherever the plugin's Contact Form 7 protection and detection logging are enabled — recommended defaults — and a submission is flagged as spam by simply failing the plugin's JavaScript token check. DB::log() then re-runs the same key-blind sanitizer and writes the JSON-encoded details into the zerospam_log table. The Detection Log details modal, rendered on a manage_options admin page, echoes that nested-array JSON unescaped — and the stored script executes in the administrator's authenticated browser session, persisting until the log entry is purged or rotated.
BitFire FREE Blocks It Before WordPress Runs
This attack arrives as an automated, unauthenticated form POST — exactly where BitFire FREE stops it. BitFire Bot Protection classifies the request before any vulnerable WordPress code executes: unknown and restricted bots cannot submit forms, POST data, or call sensitive endpoints, and clients presenting as browsers must pass lightweight JavaScript verification that real browsers normally pass while scripts and fake browsers often fail. BitFire's WAF inspects what the request contains — form fields and POST bodies — and detects malicious JavaScript injection, including common evasion patterns. Because the exploit's markup must ride inside the POST body, it crosses the WAF's inspection boundary. Both controls ship in BitFire FREE for eligible non-commercial websites; commercial sites need an appropriate commercial license. Allowed bots bypass bot restrictions — never WAF enforcement.
Fixed in 5.7.11: Sanitize Keys, Escape Output
Zero Spam 5.7.11 breaks the chain at two layers. Utilities::sanitize_array() now sanitizes string keys with sanitize_text_field() at every nesting level and rebuilds the array, so raw markup never reaches the database; the rewrite also fixes a latent bug where recursive calls dropped the requested sanitizer type. The Detection Log details modal now wraps its JSON output in esc_html(), which neutralizes log entries stored before the upgrade as well. Update immediately — every version through 5.7.10 keeps this stored-script path open.
If Your Site Was Affected, Investigate for Persistence.
Patching closes the known path; it does not undo a compromise that already happened. An administrator who opened a poisoned log entry ran attacker-controlled scripts in their authenticated session, and attackers rarely stop at one foothold. Run BitFire Threat Hunter, a thorough post-compromise investigation that uncovers backdoor WordPress administrator accounts, hidden database triggers, long-running PHP processes, and droppers that can restore malware or reinfect the site. Remove every persistence mechanism it finds, then rotate administrator and other relevant credentials. A clean-looking Detection Log is not proof your site is clean.
Stop the Next Attack at the Request Layer
Zero Spam's flaw proves a simple point: anything a stranger can POST to your site eventually gets read by an admin. BitFire stops the attack where it starts — Bot Protection shuts out automated form submissions and the WAF inspects the payload before WordPress processes it, behavior-based controls that stop even unknown CVEs. Update Zero Spam to 5.7.11 or later, run Threat Hunter if the vulnerable version was ever live, and put BitFire in front of the next attack. Start with BitFire FREE today.