WP Cerber Security 9.9
At a Glance
WP Cerber 9.9 is here, and this release is all about resilience. We built a self-healing mechanism for your plugin settings, closed several detection bypasses in the Traffic Inspector’s obfuscated JavaScript detector, and fixed a class of fatal errors that could take a site down on certain hosting environments. If you run WP Cerber on a busy site or on legacy hosting, this update makes your installation noticeably more robust.
Key Highlights
- New: Automatic backup and recovery for plugin settings, with clear reporting when a recovery happens.
- Security: Multiple hardening rounds for the obfuscated JavaScript detector used by the Traffic Inspector, closing real bypass vectors.
- Reliability: WP Cerber now works correctly on legacy hosting environments where PHP lacks the modern mysqlnd database driver.
- Bugfixes: A site-crashing settings corruption scenario on PHP 8 is fixed, along with a detection regression for hex-escaped JavaScript.
New Features
Automatic Backup and Recovery for Plugin Settings
This is the headline feature of the release. WP Cerber now maintains a last-known-valid copy of its configuration in the plugin’s key-value storage. The backup is refreshed after every successful settings update, settings import, plugin upgrade, and by the daily maintenance task. Only valid configurations are allowed to replace the existing backup, so a bad state can never overwrite a good one.
Why does this matter? If the stored plugin configuration in the database ever becomes unreadable, WP Cerber detects the corruption and automatically restores the configuration from the backup. You keep your firewall rules, access lists, and notification settings instead of silently falling back to factory defaults.
The recovery process is fully transparent. Every outcome is reported through the plugin’s issue monitor:
- After a successful automatic restoration, you see a dismissible warning explaining what happened, what action was taken, and what you should review. The notice resolves itself after you review and save your settings.
- If the backup is missing, invalid, or the recovery fails, a critical issue is registered with actionable guidance and relevant diagnostic metadata, without exposing serialized settings or storage internals.
- Contradictory or duplicate issue states are prevented, so you never see conflicting notices.
If recovery is not possible, the existing last-resort fallback to default settings is preserved, and those default settings are now persisted to the database so the plugin starts from a deterministic state. We also hardened the restore path against stale option caches: the corrupted value is explicitly deleted before the restored value is written, and the backup is stored and loaded bypassing the object cache, so only the durable database record is trusted.
Advisory Notice for Hosts Without the mysqlnd Driver
A new advisory detector in the “System Readiness” widget identifies servers where PHP’s mysqli extension is built against the legacy libmysqlclient library instead of modern mysqlnd. The notice is informational. It confirms that WP Cerber keeps working through a compatible fallback and recommends enabling mysqlnd for full compatibility and better performance. This gives you a concrete, actionable diagnostic to bring to your hosting provider.
Security and Access Control Changes
Hardened Detection of Obfuscated JavaScript in the Traffic Inspector
The Traffic Inspector inspects public request fields for obfuscated JavaScript, and this release closes several coverage gaps and bypass vectors in that detector while preserving its low false-positive model.
Broader escape-sequence coverage. The detector previously recognized only \xNN hex escapes in fully escaped strings. It now also detects \uNNNN and \u{...} Unicode escapes, including strings that mix the supported formats. Decoding is restricted to ASCII code points, and partial escapes and arbitrary expressions remain deliberately out of scope to avoid false positives.
Detection of primitives hidden in fromCharCode() calls. Payloads decoded from explicit String.fromCharCode() constructions are now checked for execution, DOM, network, and system primitives, not just external URLs and IP addresses. Decoding is restricted to validated decimal and hexadecimal literals, supports multiple calls, uppercase 0X prefixes, and optional trailing commas, and applies JavaScript ToUint16 semantics so decoded values match what a browser would actually produce. Token-aware primitive matching with identifier boundaries means ordinary words such as “description” and “evaluation” are no longer matched on the eval or script substrings.
Mitigation of wrapped integer bypasses. String.fromCharCode() applies ToUint16 to every argument, so an ASCII code plus a multiple of 65536 yields the same character. The detector previously accepted only up to six-digit literals, which meant wrapped seven-or-more-digit values bypassed detection entirely. The detector now accepts unsigned decimal and hexadecimal literals up to JavaScript’s Number.MAX_SAFE_INTEGER and reduces each token deterministically to its ToUint16 code unit, independent of the platform’s integer size. Token length is bounded during conversion, so an oversized literal cannot drive unbounded per-digit work on a public request, closing a potential DoS vector.
No suppression via a single bad token. Previously, one out-of-range or ambiguous token dropped the entire decoded call, so an attacker could append a single unsupported value to an otherwise detectable payload and suppress detection. A structurally valid but unsupported token is now mapped to a sentinel character and the rest of the call is still decoded. The whole call is skipped only when the argument list is malformed or non-numeric.
Comment-separated payloads are no longer a blind spot. The detector’s input compaction removed only generic whitespace, which left JavaScript comments intact and allowed comment-separated numeric arguments such as String.fromCharCode(101,/*x*/118,97,108,40,49,41,59) to bypass detection. The detector now strips JS block comments, line comments, and lexical whitespace outside quoted strings before running its heuristics, and it handles argument lists that span multiple lines.
For a WordPress site owner, the practical outcome is straightforward: several realistic techniques an attacker could use to sneak obfuscated JavaScript past the Traffic Inspector no longer work, and the detector remains conservative enough not to flag legitimate traffic.
Reliability Improvements
Compatibility with Legacy Database Drivers
WP Cerber now works correctly on hosting environments where PHP does not provide the modern mysqlnd database driver. The database layer checks for mysqli_fetch_all() availability before taking the mysqlnd fast path. When it is unavailable, result sets are fetched row by row through a compatible method, preserving row order, result shapes, and the existing error-handling contract. Instead of a fatal error, you get a slower but fully functional fallback, plus the advisory notice described above.
Bugfixes
Fatal Error on Sites with Corrupted Settings (PHP 8)
A corrupted, non-unserializable configuration value in the database caused a fatal TypeError in array_merge() at plugin load time on PHP 8, taking the whole site down. Settings loading now validates the stored value and falls back to the default settings when it cannot be parsed. The failure is registered as a persistent critical issue and is resolved automatically when the administrator re-saves the settings. The corruption issue fires only when a non-empty stored value genuinely fails to unserialize, so an empty value, which simply means the settings do not exist yet, never triggers a false alarm. Combined with the new backup and recovery feature, this turns a site-crashing scenario into a self-healing one.
Fatal Error on Hosts Without mysqlnd
The database layer called mysqli_result::fetch_all(), which requires the mysqlnd driver and does not exist on hosts running mysqli against libmysqlclient, causing a fatal error. The fast path is now guarded and falls back to row-by-row fetching, as described in the reliability section above.
Regression in Hex-Escaped JavaScript Detection
A regression in the obfuscated JavaScript detector prevented strings made solely of \xNN sequences from being decoded. The normalization step used trim() with a character mask that stripped the leading backslash of the first escape along with the opening quote, producing an odd-length string that the decoding guard then skipped. As a result, hex-escaped primitives such as eval, script, and XMLHttpRequest went undetected on the default-enabled Traffic Inspector request-field path. The decoding now works correctly, restoring detection of these obfuscated primitives.
Bypass via Comment-Separated fromCharCode Arguments
Valid comment-separated numeric arguments in fromCharCode() calls bypassed detection because JavaScript comments were left intact during input compaction. This is fixed as described in the security section above.
Summary
Version 9.9 is a release you will hopefully never notice, and that is the point. Your settings now survive database corruption instead of vanishing. A hosting environment quirk that used to crash the plugin now degrades gracefully and tells you exactly what to ask your host to fix. For the administrator, the daily experience is the same familiar dashboard, running on a foundation that recovers from failure on its own and inspects hostile traffic with fewer blind spots.
Have any questions?
If you have a question regarding WordPress security or WP Cerber, leave them in the comments section below or get them answered here: G2.COM/WPCerber.