{"id":305505,"date":"2026-05-17T21:18:45","date_gmt":"2026-05-17T21:18:45","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/zerobot-security\/"},"modified":"2026-10-06T12:03:10","modified_gmt":"2026-10-06T12:03:10","slug":"zerobot-security","status":"publish","type":"plugin","link":"https:\/\/roh.wordpress.org\/plugins\/zerobot-security\/","author":23485054,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.1.1","stable_tag":"1.1.1","tested":"7.1.3","requires":"5.8","requires_php":"7.4","requires_plugins":null,"header_name":"ZeroBot Security \u2013 Login Protection, Firewall & Bot Blocker","header_author":"ZeroBot","header_description":"Full-stack antibot, firewall, captcha, and threat intelligence for WordPress \u2014 powered by the ZeroBot platform.","assets_banners_color":"0d1325","last_updated":"2026-10-06 12:03:10","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"https:\/\/zerobot.info","rating":0,"author_block_rating":0,"active_installs":0,"downloads":517,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.15":{"tag":"1.0.15","author":"zerobot","date":"2026-05-17 21:16:53","revision":3534866},"1.0.17":{"tag":"1.0.17","author":"zerobot","date":"2026-05-18 14:58:14","revision":3535789},"1.1.0":{"tag":"1.1.0","author":"zerobot","date":"2026-10-05 18:02:07","revision":3729408},"1.1.1":{"tag":"1.1.1","author":"zerobot","date":"2026-10-06 12:03:10","revision":3730739}},"upgrade_notice":{"1.1.1":"<p>In-plugin signup now requires the email of a site administrator.<\/p>","1.1.0":"<p>Free login protection and XML-RPC blocking now work without an account, and IP detection can no longer be spoofed. Recommended for all sites.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3534888,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3534888,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3534940,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3534940,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.15","1.0.17","1.1.0","1.1.1"],"block_files":[],"assets_screenshots":[],"screenshots":[]},"plugin_section":[262246],"plugin_tags":[7665,2439,1174,1229,600],"plugin_category":[44,54],"plugin_contributors":[263289],"plugin_business_model":[],"class_list":["post-305505","plugin","type-plugin","status-publish","hentry","plugin_section-dashboard-widgets","plugin_tags-antibot","plugin_tags-brute-force","plugin_tags-firewall","plugin_tags-login-security","plugin_tags-security","plugin_category-discussion-and-community","plugin_category-security-and-spam-protection","plugin_contributors-zerobot","plugin_committers-zerobot"],"banners":{"banner":"https:\/\/ps.w.org\/zerobot-security\/assets\/banner-772x250.png?rev=3534940","banner_2x":"https:\/\/ps.w.org\/zerobot-security\/assets\/banner-1544x500.png?rev=3534940","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/zerobot-security\/assets\/icon-128x128.png?rev=3534888","icon_2x":"https:\/\/ps.w.org\/zerobot-security\/assets\/icon-256x256.png?rev=3534888","generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>ZeroBot Security protects your site from the first minute, with no account and no setup.\nActivate it and two protections start working inside WordPress itself.\nNothing is sent anywhere.<\/p>\n\n<h4>Free, no account needed<\/h4>\n\n<ul>\n<li><strong>Login Brute-Force Guard<\/strong> \u2014 Counts failed logins per IP and locks the IP out after 5 attempts\nfor 15 minutes (both adjustable). Blocks password-guessing bots on wp-login.php.<\/li>\n<li><strong>XML-RPC Kill Switch<\/strong> \u2014 Shuts down xmlrpc.php, the endpoint bots use to try hundreds of\npasswords in one request and to abuse pingbacks. Skipped automatically when Jetpack is active,\nbecause Jetpack needs it.<\/li>\n<li><strong>Attack counter<\/strong> \u2014 The dashboard shows how many failed logins, lockouts and XML-RPC requests\nwere stopped over the last 7 days.<\/li>\n<li><strong>Spoof-proof IP detection<\/strong> \u2014 Proxy headers are only trusted from real Cloudflare edges and\nlocal reverse proxies, so attackers cannot fake their IP to dodge a lockout.<\/li>\n<\/ul>\n\n<h4>Network protection (free 7-day trial, then a ZeroBot plan)<\/h4>\n\n<p>Connect the site from the plugin dashboard: enter your email, confirm it, and the plugin activates\nitself. The trial includes 100 IP checks and needs no credit card.<\/p>\n\n<ul>\n<li><strong>Site-Wide Firewall<\/strong> \u2014 Switches on automatically when you connect. Every public request is\nchecked against IPs, VPNs, Tor nodes and datacenters seen attacking the ZeroBot network, with\noptional country rules. If ZeroBot is slow to answer, the visitor is let through after 3 seconds.<\/li>\n<li><strong>Browser Fingerprint<\/strong> \u2014 Detects headless browsers, VMs and automation frameworks.<\/li>\n<li><strong>Comment Guard<\/strong> \u2014 Blocks bot comments before they are saved.<\/li>\n<li><strong>REST API Guard<\/strong> \u2014 Screens public REST calls, with configurable exempt routes.<\/li>\n<li><strong>Shared blacklist<\/strong> \u2014 IPs locked out by the login guard are pushed to your ZeroBot blacklist\nand blocked on every site you connect.<\/li>\n<\/ul>\n\n<p>When a trial or plan ends, network protection pauses and the free protections keep running.<\/p>\n\n<h4>Full Platform Management<\/h4>\n\n<ul>\n<li><strong>Domain Rules<\/strong> \u2014 Create, edit, and delete antibot rules from inside wp-admin.<\/li>\n<li><strong>Whitelist<\/strong> \u2014 IPs, CIDR ranges, and ASNs scoped per service. Bulk import supported.<\/li>\n<li><strong>Blacklist<\/strong> \u2014 Same scoping and bulk import as the whitelist.<\/li>\n<li><strong>Threat Logs<\/strong> \u2014 Filterable, paginated viewer of every traffic event with CSV export.<\/li>\n<li><strong>Dashboard<\/strong> \u2014 Live stats, 7-day traffic chart, recent threats, account info.<\/li>\n<\/ul>\n\n<h4>Other Features<\/h4>\n\n<ul>\n<li>Cloudflare and reverse-proxy IP detection that cannot be spoofed by visitors<\/li>\n<li>Decision cache via WordPress object cache (Redis\/Memcached) with transient fallback<\/li>\n<li>Fail-open by default \u2014 never breaks your site if the API is unreachable<\/li>\n<li>Daily license verification via wp-cron<\/li>\n<li>WP-admin dashboard widget showing bots\/humans (24h)<\/li>\n<li>Pure PHP + vanilla JS \u2014 no jQuery, no React, no external CDN<\/li>\n<\/ul>\n\n<h3>External Services<\/h3>\n\n<p>The free protections (login guard, XML-RPC kill switch) run entirely inside WordPress and\ncontact no external service. The plugin only contacts ZeroBot after the administrator either\nsubmits the \"Turn on network protection\" form or enters a license key.<\/p>\n\n<p><strong>0. ZeroBot account signup (https:\/\/zerobot.info\/v3\/wp\/connect)<\/strong><\/p>\n\n<ul>\n<li>What it does: Creates a free ZeroBot trial account from inside wp-admin.<\/li>\n<li>When it's called: Only when the administrator types an email, ticks the consent box and clicks\n\"Start free trial\". While the account waits for email confirmation, the open admin page checks\nevery 10 seconds whether it has been confirmed.<\/li>\n<li>Data transmitted: The email address entered (it must belong to an administrator of the site),\nthis site's domain and home URL, the plugin version and the server's IP address. During signup\nZeroBot fetches a one-time confirmation from the site, including a keyed hash of that email.\nZeroBot then sends an activation email to that address.<\/li>\n<li>What it returns: A one-time claim code, then the license key once the email is confirmed.<\/li>\n<li>Terms &amp; Privacy: https:\/\/zerobot.info\/terms \u2014 https:\/\/zerobot.info\/policy<\/li>\n<\/ul>\n\n<p><strong>1. ZeroBot API (https:\/\/zerobot.info)<\/strong><\/p>\n\n<ul>\n<li>What it does: Classifies visitors as human or bot, synchronizes domain rules \/ whitelists \/\nblacklists, and returns threat log data for the dashboard.<\/li>\n<li>When it's called: On every public request that one of the enabled protection layers handles\n(Firewall, Page Protection, Login Guard, Comment Guard, REST API Guard). Also called from the\nadmin dashboard for stats, rules, lists, and traffic logs. Also called once per day by\nwp-cron for license verification.<\/li>\n<li>Data transmitted: Visitor IP address, user agent, current URL host, site domain, and the\nplugin's license key. No post content, no customer personal data, no form submissions.<\/li>\n<li>What it returns: A JSON decision object (<code>is_bot<\/code>, <code>reason<\/code>, <code>risk_score<\/code>, optional\n  captcha_html), plan metadata, and aggregate stats for the dashboard.<\/li>\n<li>Terms &amp; Privacy: https:\/\/zerobot.info\/terms \u2014 https:\/\/zerobot.info\/policy<\/li>\n<\/ul>\n\n<p><strong>2. ZeroBot Fingerprint Collector (https:\/\/zerobot.info\/fingerprint\/index.js)<\/strong><\/p>\n\n<ul>\n<li>What it does: Collects client-side browser signals (canvas, WebGL, fonts, behavior) to detect\nheadless browsers, VMs, and automation frameworks.<\/li>\n<li>When it's loaded: Injected on public pages and the login screen ONLY when the administrator\nenables \"Browser Fingerprint\" in Protection Settings. It is disabled by default; the plugin\ndoes not load any external JavaScript out of the box.<\/li>\n<li>Data transmitted: Browser fingerprint signals and the visitor's IP address. No WordPress\nuser data, no cookies, no form data.<\/li>\n<li>What it returns: A risk score used to decide whether a visitor should face a soft challenge.<\/li>\n<li>Terms &amp; Privacy: https:\/\/zerobot.info\/terms \u2014 https:\/\/zerobot.info\/policy<\/li>\n<\/ul>\n\n<p><strong>3. FlagCDN (https:\/\/flagcdn.com)<\/strong><\/p>\n\n<ul>\n<li>What it does: Serves tiny country-flag PNG images for the admin-only traffic log.<\/li>\n<li>When it's loaded: Only inside wp-admin, only when the administrator opens the Dashboard or\nThreat Logs page. It is never loaded on the public site. Only 2-letter ISO country codes are\ntransmitted as part of the image URL.<\/li>\n<li>Data transmitted: The 2-letter country code and standard image-request metadata. No visitor\ndata, no WordPress data, no cookies.<\/li>\n<li>Service homepage: https:\/\/flagcdn.com<\/li>\n<\/ul>\n\n<p>If you do not wish to transmit any data to ZeroBot, do not connect the site. The free\nprotections keep working without any external connection.<\/p>\n\n<h3>Privacy<\/h3>\n\n<p>This plugin does not store visitor personal data in your WordPress database beyond IP\naddresses in the local threat-log table (<code>wp_zb_threats<\/code>, dropped on uninstall). It does\nnot set any cookies on visitors. Data sent to the ZeroBot service is described in the\nExternal Services section above.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Install from Plugins \u2192 Add New (search \"ZeroBot Security\"), or upload the zip.<\/li>\n<li>Activate the plugin. Login protection and the XML-RPC kill switch are on right away.<\/li>\n<li>Optional: open <strong>ZeroBot \u2192 Dashboard<\/strong> and, under \"Turn on network protection\", enter the email\nof an administrator of this site and click \"Start free trial\" (7 days, 100 IP checks, no card).\nClick the link in the activation email: the site connects and the firewall switches on.\nAlready have a ZeroBot license key? Paste it under <strong>ZeroBot \u2192 License<\/strong>.<\/li>\n<li>Adjust the layers in <strong>ZeroBot \u2192 Protection<\/strong>.<\/li>\n<\/ol>\n\n<p>No account is needed for the free protections.<\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"do%20i%20need%20an%20account%3F\"><h3>Do I need an account?<\/h3><\/dt>\n<dd><p>No. Login brute-force protection and the XML-RPC kill switch work right after activation, with\nno account and no data leaving your site. An account is only needed for network protection.<\/p><\/dd>\n<dt id=\"what%20happens%20when%20my%20trial%20ends%3F\"><h3>What happens when my trial ends?<\/h3><\/dt>\n<dd><p>Network protection pauses and the free protections keep running. If you activate a plan later,\nthe plugin notices within a day (or immediately with \"Check again\") and switches it back on.<\/p><\/dd>\n<dt id=\"i%20use%20cloudflare%20or%20another%20proxy.%20will%20lockouts%20hit%20the%20right%20ip%3F\"><h3>I use Cloudflare or another proxy. Will lockouts hit the right IP?<\/h3><\/dt>\n<dd><p>Cloudflare and local reverse proxies (for example nginx in front of Apache) are detected\nautomatically. Behind another CDN, enable \"Trust proxy headers\" in Protection Settings and\ncheck \"Your detected IP\" on the License page.<\/p><\/dd>\n<dt id=\"i%20use%20jetpack.%20is%20xml-rpc%20still%20blocked%3F\"><h3>I use Jetpack. Is XML-RPC still blocked?<\/h3><\/dt>\n<dd><p>No. Jetpack connects to WordPress.com through XML-RPC, so the kill switch stands down while\nJetpack is active. Login protection still runs.<\/p><\/dd>\n<dt id=\"will%20this%20plugin%20break%20my%20site%20if%20the%20zerobot%20api%20is%20down%3F\"><h3>Will this plugin break my site if the ZeroBot API is down?<\/h3><\/dt>\n<dd><p>No. The default Fail Mode is \"Fail Open\" \u2014 visitors are allowed through silently and the\nincident is logged to the PHP error log. You can switch to Fail Closed in Protection\nSettings if you prefer strict security.<\/p><\/dd>\n<dt id=\"how%20much%20does%20it%20call%20the%20zerobot%20api%3F\"><h3>How much does it call the ZeroBot API?<\/h3><\/dt>\n<dd><p>Every visitor decision is cached per-IP for 24 hours by default, so repeat visitors do not\ntrigger additional API calls. A page that gets 1,000 hits\/hour from returning visitors\ntypically results in only a handful of API calls.<\/p><\/dd>\n<dt id=\"does%20the%20fingerprint%20collector%20always%20run%3F\"><h3>Does the fingerprint collector always run?<\/h3><\/dt>\n<dd><p>No. The fingerprint collector is disabled by default and only injects on the public site\nwhen the administrator turns on \"Browser Fingerprint\" under Protection Settings.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20woocommerce%3F\"><h3>Does it work with WooCommerce?<\/h3><\/dt>\n<dd><p>Yes \u2014 the REST API Guard auto-exempts <code>\/wc\/store\/<\/code> routes. Add other custom routes to the\nexempt list as needed.<\/p><\/dd>\n<dt id=\"does%20it%20support%20multisite%3F\"><h3>Does it support multisite?<\/h3><\/dt>\n<dd><p>Single-site only for now.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.1.1<\/h4>\n\n<ul>\n<li>Security: a ZeroBot account can only be created from the plugin with the email of an\nadministrator of the site. ZeroBot also confirms this with the site during signup.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>New: free protection without an account. The Login Brute-Force Guard and the XML-RPC kill\nswitch now run as soon as the plugin is active. Previously every protection waited for a\nlicense key, so new installs protected nothing.<\/li>\n<li>New: create a ZeroBot trial account from inside wp-admin. Enter an email, confirm it, and\nthe plugin activates itself. Pasting an existing license key still works.<\/li>\n<li>New: free dashboard with 7-day counts of failed logins, lockouts and blocked XML-RPC requests.<\/li>\n<li>New: when a plan or trial ends, network protection pauses with a clear notice and the free\nlayer keeps running. A daily check re-enables it automatically after renewal.<\/li>\n<li>Security: visitor IP detection no longer trusts proxy headers sent by the visitor.\nCF-Connecting-IP is only accepted from Cloudflare edges, and X-Real-IP \/ X-Forwarded-For\nonly from local reverse proxies or when \"Trust proxy headers\" is enabled. Forged headers\ncould previously bypass the login lockout or lock out someone else's IP. The old default\nof trusting all proxy headers is switched off on update.<\/li>\n<li>Fix: a temporary API outage during the daily license check no longer switches network\nprotection off until the next day.<\/li>\n<li>Fix: the XML-RPC kill switch stands down while Jetpack is active.<\/li>\n<li>Fix: a visitor flagged as a bot was kept blocked for 24 hours, even after being whitelisted.\nBot verdicts are now cached for 15 minutes, and whitelisting an IP from the plugin applies\nimmediately.<\/li>\n<li>Change: the Site-Wide Firewall is on by default and switches on whenever a site is connected.<\/li>\n<li>Change: without a valid license, the network layers (firewall, browser fingerprint, comment\nand REST API guards, shared blacklist) are shown off and cannot be switched on.<\/li>\n<li>Fix: the firewall now gives up after 3 seconds with no retries if the API is slow (it could\npreviously hold a page for up to 24 seconds before failing open).<\/li>\n<li>Fix: when the trial checks are used up or the plan ends, the firewall pauses its API calls for\nan hour instead of calling on every page view, and the dashboard explains why.<\/li>\n<li>Fix: the master protection switch is on for new installs. On update it is turned on only\nfor sites that never saved the settings page.<\/li>\n<li>Tested with WordPress 7.1.<\/li>\n<\/ul>\n\n<h4>1.0.17<\/h4>\n\n<ul>\n<li>New: searchable multi-country picker on the Protection Settings page.\nReplaces the plain-text \"Allowed Countries\" input with a chip-based UI\nthat lists all 249 ISO countries with flag emoji, alphabetical search,\nand a clear \"Allow all \/ Only specific\" mode toggle.<\/li>\n<li>Fix: visitors blocked by country policy now correctly show a yellow\n\"Denied\" badge on the Dashboard's Recent Activity widget. They were\npreviously stacked into the red \"Bot\" bucket even though the block\nreason was \"Country Denied (XX)\".<\/li>\n<li>Fix: country flags now render in both the Dashboard widget and the\nThreat Logs table. The flag helper expects a 2-letter ISO code, but the\nAPI ships the country as a name -- so flags silently failed for every\nrow. A new <code>Helpers::countryNameToCode()<\/code> lookup resolves names to\ncodes, and the flag image renders before the country name on every\nlog row.<\/li>\n<li>Change: removed the Score column from the Dashboard Recent Activity\nwidget and the Threat Logs table. The Reason already explains why a\nrequest was flagged, and the numeric score added visual noise without\ndecision-relevant information.<\/li>\n<li>Security: tightened the firewall verdict cache to bot-only. Clean\nverdicts are no longer cached, so an IP that turns malicious mid-cache\ndoesn't keep passing through for up to 24 hours. Bot verdicts continue\nto be cached for instant re-blocking.<\/li>\n<li>Compliance: <code>$_SERVER['REQUEST_URI']<\/code> in <code>XmlRpcGuard::register()<\/code> is\nnow run through <code>wp_unslash()<\/code> and <code>sanitize_text_field()<\/code> before the\nregex match, clearing the two PHPCS warnings about that variable.<\/li>\n<\/ul>\n\n<h4>1.0.16<\/h4>\n\n<ul>\n<li>Fix: critical error on every wp-admin page caused by a missing\n  License::isDomainAuthorized() method that the <code>admin_notices<\/code> hook called.\nThe method now exists on the License class, fails open when no\nauthorization state has been recorded yet, and gets set true\/false by\n  activate() based on whether the auto domain-registration call to the\nZeroBot platform succeeded (HTTP 200) or reported the domain as already\nregistered (HTTP 409).<\/li>\n<\/ul>\n\n<h4>1.0.15<\/h4>\n\n<ul>\n<li>WordPress.org review compliance: removed the broken <code>flagpedia.net\/privacy<\/code>\nURL from the External Services section of readme.txt.<\/li>\n<li>The chart-data bootstrap on the admin dashboard now ships via\n  wp_add_inline_script() attached to the existing <code>zerobot-security-admin<\/code>\nhandle, instead of an inline <code>&lt;script&gt;<\/code> tag. No behavioural change \u2014 the\nsame JS payload is delivered through the official WordPress enqueue API.<\/li>\n<\/ul>\n\n<h4>1.0.14<\/h4>\n\n<ul>\n<li>WordPress.org review compliance: replaced the short \"zb_\" prefix everywhere\nit appeared in PHP and JS (AJAX action names, option keys, transient keys,\nnonce names, cron hooks, JS globals, custom DB table names, WP_Error codes,\nand the admin script handle) with the full \"zerobot_security_\" prefix so\nevery plugin-defined identifier is at least the WP.org-required 4 characters\nand is uniquely namespaced.<\/li>\n<li>No functional or UI changes \u2014 the rename is purely cosmetic (CSS class\nnames beginning with \"zb-\" are stylesheet-internal and were left\nunchanged, since they don't conflict with WordPress core or other plugins).<\/li>\n<\/ul>\n\n<h4>1.0.12<\/h4>\n\n<ul>\n<li>Second Plugin Check compliance pass: final 3 errors resolved (wrap\ncountryFlagImg() output in wp_kses(); add translators comment for\n\"Cleared %d cached decisions\"; etc.). Input-sanitization warnings\naddressed across Helpers, Firewall, ProtectionSettings, LicensePage.<\/li>\n<li>Fingerprint script now passes the plugin version to wp_enqueue_script()\nfor reliable cache-busting.<\/li>\n<li>Uninstall variables renamed to zerobot_security_* prefix.<\/li>\n<\/ul>\n\n<h4>1.0.11<\/h4>\n\n<ul>\n<li>Full Plugin Check compliance pass: wrap every Helpers::icon() SVG output\nthrough wp_kses() with a tight SVG tag allowlist; add wp_unslash() +\nsanitize calls on every $<em>SERVER \/ $_POST \/ $_GET read; gate error_log()\nbehind WP_DEBUG; replace date() with gmdate(); rename plugin constants to\nZEROBOT_SECURITY<\/em>* prefix; drop load_plugin_textdomain (WP 4.6+ auto-loads\ntranslations); add translators comments for all placeholders; LoginGuard\nqueries use esc_sql() for the table identifier; uninstall uses prefixed\nvariables and prepared statements.<\/li>\n<li>Fingerprint script now enqueued via <code>wp_enqueue_script()<\/code> with a\n  script_loader_tag filter for the data attributes, replacing the raw\n  echo ''. Respects standard WordPress script filters.<\/li>\n<li>DecisionCache::flush() no longer issues a raw LIKE query \u2014 iterates the\nmatching transient option names and calls <code>delete_transient()<\/code> for each,\nso the object cache and transient DB stay in sync.<\/li>\n<li>Threat Logs are now always scoped to the current WordPress site's host (the\n\"Domain\" filter is removed \u2014 it's redundant and could leak cross-domain data).<\/li>\n<li>Firewall self-heals domain-deauthorization in real time: the plugin flags the\nsite immediately on the first failed API call instead of waiting for the\ndaily verify cron, so the warning banner shows up right after the admin\nremoves the domain from authorized_domains.<\/li>\n<li>Admin warning banner is now shown on every wp-admin page, not only the\nplugin's own screens.<\/li>\n<li>Country flags in the Dashboard and Threat Logs render as reliable PNG\nimages (via flagcdn.com) instead of Unicode emoji, which some platforms\ndon't render.<\/li>\n<\/ul>\n\n<h4>1.0.9<\/h4>\n\n<ul>\n<li>Per-IP decision cache extended to 24 hours to reduce API load<\/li>\n<li>Allowed-countries enforcement moved server-side so denied requests are logged correctly<\/li>\n<li>Login verification (device 2FA) toggle added per user<\/li>\n<\/ul>\n\n<h4>1.0.8<\/h4>\n\n<ul>\n<li>Browser Fingerprint layer now also injects on wp-login.php and via wp_footer fallback<\/li>\n<li>Fingerprint collector no longer skipped for logged-in users (configurable)<\/li>\n<\/ul>\n\n<h4>1.0.7<\/h4>\n\n<ul>\n<li>\"Country Denied\" badge styled distinctly from generic bot block<\/li>\n<li>Threat Logs show the visitor path alongside IP \/ ISP \/ country<\/li>\n<\/ul>\n\n<h4>1.0.6<\/h4>\n\n<ul>\n<li>\/v3\/openapi now receives allowed_countries from the plugin so geo-blocks are enforced\nserver-side and logged with the correct reason<\/li>\n<\/ul>\n\n<h4>1.0.5<\/h4>\n\n<ul>\n<li>Decision caching logic refactored so every request logs correctly<\/li>\n<li>Fingerprint injection improvements<\/li>\n<\/ul>\n\n<h4>1.0.3 - 1.0.4<\/h4>\n\n<ul>\n<li>\"Clear Threats for this Domain\" action in Threat Logs<\/li>\n<li>\"Path\" column in Threat Logs showing the URL the visitor accessed<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release<\/li>\n<li>Full Dashboard, License, Rules, Whitelist, Blacklist, Protection Settings, Threat Logs<\/li>\n<li>Six protection layers: Page, Firewall, Login, Comment, REST API, XML-RPC<\/li>\n<li>Decision caching with object cache + transient fallback<\/li>\n<li>CSV export for threat logs<\/li>\n<li>WP-admin dashboard widget<\/li>\n<li>Cloudflare \/ proxy IP detection<\/li>\n<\/ul>","raw_excerpt":"Free brute-force login protection and XML-RPC blocking, plus an optional bot firewall backed by the live ZeroBot threat network.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/roh.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/305505","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/roh.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/roh.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/roh.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=305505"}],"author":[{"embeddable":true,"href":"https:\/\/roh.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/zerobot"}],"wp:attachment":[{"href":"https:\/\/roh.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=305505"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/roh.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=305505"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/roh.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=305505"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/roh.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=305505"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/roh.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=305505"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/roh.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=305505"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}