diff --git a/cdn-files/plugin-info.json b/cdn-files/plugin-info.json
index 4878d76..cff3679 100644
--- a/cdn-files/plugin-info.json
+++ b/cdn-files/plugin-info.json
@@ -1,17 +1,17 @@
{
"name": "WebDecoy Bot Detection",
"slug": "webdecoy",
- "version": "2.10.2",
+ "version": "2.10.3",
"author": "WebDecoy",
"author_profile": "https://webdecoy.com",
"requires": "6.1",
"tested": "7.1",
"requires_php": "7.4",
- "download_url": "https://cdn.webdecoy.com/wordpress/webdecoy-2.10.2.zip",
+ "download_url": "https://cdn.webdecoy.com/wordpress/webdecoy-2.10.3.zip",
"sections": {
"description": "
WebDecoy provides enterprise-grade bot detection and fraud protection for WordPress websites. Unlike simple CAPTCHA solutions, WebDecoy uses a layered defense approach that analyzes visitors from multiple angles — including deterministic tripwires that catch scanners with zero false positives.
Key Features
- Deterministic tripwires (hidden honeypot paths) — zero-false-positive bot blocking
- Server-side and client-side bot detection
- Invisible proof-of-work challenge (no external CAPTCHA service)
- Comment, login, and registration spam protection
- WooCommerce carding attack prevention
- 60+ good bots automatically allowed
- AI crawler detection and blocking
- Optional WebDecoy Cloud: centralized dashboard, rotation-proof device lockouts, and WAF integrations (push confirmed attackers to Cloudflare or AWS WAF — blocked before they reach WordPress)
",
"installation": "- Upload the plugin files to
/wp-content/plugins/webdecoy - Activate the plugin through the Plugins menu
- Tripwires and local protection are active out of the box — no API key required
- Optionally go to WebDecoy > Settings > WebDecoy Cloud to connect for centralized monitoring and enforcement
",
- "changelog": "2.10.2
- Fixed: pages no longer wait up to 20 seconds when WebDecoy Cloud is slow or unreachable. Detections are sent after the page is delivered, and cloud calls pause for a minute while WebDecoy is unavailable.
2.10.1
- Fixed: 2.10.0 stopped sites loading with a fatal error, "Class WebDecoy_AI_Referrals not found".
2.10.0
- Added: when connected to WebDecoy Cloud, the plugin counts visits that AI products such as ChatGPT, Claude, Perplexity and Gemini send to your site, for your AI Traffic page. Only the product name, the landing path and a count are sent; nothing about the visitor.
2.9.1
- Fixed: AI search crawlers and assistants fetching a page for a person are no longer identified as AI training crawlers (Claude-User, Claude-SearchBot, MistralAI-User; PerplexityBot is now a search crawler, as Perplexity documents it).
- Changed: with Block AI crawlers on, PerplexityBot and Claude-SearchBot are let through like other AI search crawlers. Assistants fetching for a person, such as ChatGPT-User and Claude-User, are still refused.
- Added: Perplexity-User, MistralAI-User, Meta-ExternalFetcher and Claude-SearchBot are recognised (186 crawlers).
2.9.0
- Added: per-path crawler rules set in WebDecoy Cloud now apply in WordPress too, by the same rule the edge sensor uses. Cloud rules can only refuse, never allow.
- Changed: crawlers are identified from the shared WebDecoy registry (182, was 54); with Block AI crawlers on, AI agents and assistants are refused along with training crawlers.
2.3.1
- Fixed: Detections forwarded from your site are now identified by the visitor's own request signature. Previously they were identified by your server's outgoing connection, which is the same for every visitor — so every visitor a site reported was grouped into a single "actor" in the dashboard. Only request header names plus Accept-Language and Accept-Encoding are sent; no header values leave your site.
2.3.0
- One-click WebDecoy Cloud connect with automatic key provisioning
- Monthly security report opt-in
- Plan entitlements sync (fails open to free)
- Fixed: Statistics charts growing unbounded with detection data
2.1.0
- JS execution verification to catch non-JS HTTP scrapers
- Challenge token meta tag on page serve; automatic page-serve reporting
2.0.0
- All detection and protection now works locally — no API key required
- Invisible proof-of-work challenge system (SHA-256, no external service)
- Behavioral scoring, statistics page, enhanced detections page
1.3.0
- Bulk IP blocking/unblocking; enhanced good bot detection (60+ bots)
",
+ "changelog": "2.10.3
- Fixed: rule violations are no longer sent twice or lost while WebDecoy is briefly unavailable, and AI referral counts refused while WebDecoy was busy are kept and sent later.
2.10.2
- Fixed: pages no longer wait up to 20 seconds when WebDecoy Cloud is slow or unreachable. Detections are sent after the page is delivered, and cloud calls pause for a minute while WebDecoy is unavailable.
2.10.1
- Fixed: 2.10.0 stopped sites loading with a fatal error, "Class WebDecoy_AI_Referrals not found".
2.10.0
- Added: when connected to WebDecoy Cloud, the plugin counts visits that AI products such as ChatGPT, Claude, Perplexity and Gemini send to your site, for your AI Traffic page. Only the product name, the landing path and a count are sent; nothing about the visitor.
2.9.1
- Fixed: AI search crawlers and assistants fetching a page for a person are no longer identified as AI training crawlers (Claude-User, Claude-SearchBot, MistralAI-User; PerplexityBot is now a search crawler, as Perplexity documents it).
- Changed: with Block AI crawlers on, PerplexityBot and Claude-SearchBot are let through like other AI search crawlers. Assistants fetching for a person, such as ChatGPT-User and Claude-User, are still refused.
- Added: Perplexity-User, MistralAI-User, Meta-ExternalFetcher and Claude-SearchBot are recognised (186 crawlers).
2.9.0
- Added: per-path crawler rules set in WebDecoy Cloud now apply in WordPress too, by the same rule the edge sensor uses. Cloud rules can only refuse, never allow.
- Changed: crawlers are identified from the shared WebDecoy registry (182, was 54); with Block AI crawlers on, AI agents and assistants are refused along with training crawlers.
2.3.1
- Fixed: Detections forwarded from your site are now identified by the visitor's own request signature. Previously they were identified by your server's outgoing connection, which is the same for every visitor — so every visitor a site reported was grouped into a single "actor" in the dashboard. Only request header names plus Accept-Language and Accept-Encoding are sent; no header values leave your site.
2.3.0
- One-click WebDecoy Cloud connect with automatic key provisioning
- Monthly security report opt-in
- Plan entitlements sync (fails open to free)
- Fixed: Statistics charts growing unbounded with detection data
2.1.0
- JS execution verification to catch non-JS HTTP scrapers
- Challenge token meta tag on page serve; automatic page-serve reporting
2.0.0
- All detection and protection now works locally — no API key required
- Invisible proof-of-work challenge system (SHA-256, no external service)
- Behavioral scoring, statistics page, enhanced detections page
1.3.0
- Bulk IP blocking/unblocking; enhanced good bot detection (60+ bots)
",
"faq": "Does WebDecoy slow down my site?
No. WebDecoy adds negligible latency; tripwire checks are a fast path lookup and clearance minting is idle-deferred.
Will it block search engines?
No. WebDecoy automatically allows 60+ known good bots including all major search engines, and tripwires only fire on hidden paths no legitimate crawler follows.
"
},
"icons": {
diff --git a/changelog.txt b/changelog.txt
index 192e2c3..bc09f46 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,5 +1,9 @@
*** WebDecoy Bot Detection Changelog ***
+= 2.10.3 - 2026-10-02 =
+* Fixed: violation reporting is no longer duplicated or lost. Every request that records a violation drains the spool at shutdown and the cron drains it too; two drains at once read the same rows and sent them twice. Drains now take an add_option() lock (a lock older than 60 seconds is taken over). A refusal from WebDecoy (no answer, 429, 5xx) keeps the rows and their attempts and pauses cloud calls for 60 seconds; before, two refused drains discarded the spool.
+* Fixed: an AI referral batch refused with 429 is kept and resent under the same id (WebDecoy deduplicates it) instead of being deleted, and flushing waits out the pause.
+
= 2.10.2 - 2026-10-02 =
* Fixed: a page view a bot scored 40 or higher on could stall for up to 20 seconds when WebDecoy Cloud was slow or down. The detection was sent inline during init, before the block decision, with a 10 second timeout, and installs without a stored organization id made a 10 second key lookup first. Detections are now queued and sent from a shutdown handler after the response (fastcgi_finish_request where available), with a 3 second timeout and the stored organization id.
* Fixed: an ingest refusal (429, 5xx, or no answer) now pauses cloud calls for 60 seconds across all requests. IP enrichment, which filter rules use during the page, skips its call while paused instead of waiting up to 2 seconds for each new IP.
diff --git a/readme.txt b/readme.txt
index 452c4c6..79e7523 100644
--- a/readme.txt
+++ b/readme.txt
@@ -4,7 +4,7 @@ Donate link: https://webdecoy.com
Tags: bot detection, security, spam protection, woocommerce, ai bots
Requires at least: 6.1
Tested up to: 7.1
-Stable tag: 2.10.2
+Stable tag: 2.10.3
Requires PHP: 7.4
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
@@ -285,6 +285,10 @@ The bundled good-bot list (sdk/src/GoodBotList.php) stores a documentation URL f
== Changelog ==
+= 2.10.3 =
+* Fixed: rule violations reported to WebDecoy Cloud could be sent twice when two page views finished at the same moment, and were discarded if WebDecoy was briefly unavailable. They are now sent once and kept until WebDecoy is back.
+* Fixed: AI referral counts refused because WebDecoy was busy are now kept and sent later instead of being dropped.
+
= 2.10.2 =
* Fixed: when WebDecoy Cloud was slow or unreachable, pages a bot scored 40 or higher on could take up to 20 seconds to load while the plugin waited to report the detection. Detections are now sent after the page has been delivered, and the plugin pauses cloud calls for a minute when WebDecoy is unavailable. Blocking and the local log never wait on the cloud.
diff --git a/webdecoy.php b/webdecoy.php
index 8d841cc..47bd734 100644
--- a/webdecoy.php
+++ b/webdecoy.php
@@ -3,7 +3,7 @@
* Plugin Name: WebDecoy Bot Detection
* Plugin URI: https://webdecoy.com/wordpress
* Description: Protect your WordPress site from bots, spam, and carding attacks with WebDecoy's advanced threat detection.
- * Version: 2.10.2
+ * Version: 2.10.3
* Requires at least: 6.1
* Requires PHP: 7.4
* Author: WebDecoy
@@ -41,7 +41,7 @@ function str_starts_with(string $haystack, string $needle): bool
}
// Plugin constants
-define('WEBDECOY_VERSION', '2.10.2');
+define('WEBDECOY_VERSION', '2.10.3');
define('WEBDECOY_PLUGIN_FILE', __FILE__);
define('WEBDECOY_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('WEBDECOY_PLUGIN_URL', plugin_dir_url(__FILE__));