=== FormGhost ===
Contributors: byabdalla
Tags: spam, antispam, honeypot, captcha alternative, gdpr
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.2.4
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Invisible 9-layer spam protection — the spam never happened. Zero CAPTCHAs. Zero cloud. 100% free. GDPR-compliant by design.

== Description ==

**The spam never happened.** FormGhost is a privacy-first WordPress antispam plugin that makes spam quietly disappear: bots are shown a fake success page and walk away believing they got through, while you never receive a thing. No CAPTCHA is ever shown, no data leaves your server, and no personally identifiable information is kept on disk. Spam goes into the Vault. Real users never see anything.

**Every feature is free. There is no Pro version, no license key, no upsell.**

= Why FormGhost =

* No CAPTCHAs. No "select all the buses." No "I'm not a robot" checkbox.
* No cloud dependency — the spam detection itself makes no external HTTP calls. The only optional exceptions (CAPTCHA verification, MX lookup) are off by default and documented under External services.
* GDPR / DSGVO friendly. IP addresses are hashed with a per-site secret before storage. Form payloads are encrypted (AES-256-GCM) in the vault.
* Ghost Response: bots see a fake success message and walk away thinking the submission worked. You never get the email.
* Blocked something legitimate? Open it in the Vault and forward it to the inbox it was headed to with one click.

= How it works =

Every submission is graded by up to nine independent layers. Each layer adds a small score. When the total crosses the configured threshold, FormGhost takes action — usually a silent Ghost Response, so the bot never learns it was blocked.

1. **Honeypot** — Daily-rotated, site-suffixed hidden fields. Different on every FormGhost site; resistant to "fill every field" bots.
2. **Timing** — Encrypted submission timestamp. Submissions that arrive too fast (or with a replayed token) fail this layer.
3. **Proof-of-Work** — Lightweight browser challenge solved by a WebWorker. Stops curl / wget / scripted submissions cold.
4. **Behavioral fingerprint** — Mouse curvature, keystroke variance, scroll, focus and touch signals computed entirely in the browser. Only the resulting score is transmitted.
5. **Rate limiting** — Per-IP and per-form submission caps with sliding windows and CIDR-aware whitelisting.
6. **Disposable email detection** — Curated disposable-domain blocklist (extensible with your own block/allow lists), optional MX heuristic.
7. **Content patterns** — Casino / SEO / pharma phrase detection with a self-learning twist.
8. **WordPress hardening** — Disable XML-RPC, harden the REST users endpoint, generic login errors, optional Application Passwords lockdown.
9. **Optional CAPTCHA** — Turnstile / hCaptcha / ALTCHA on the core WordPress forms you choose (comments, login, registration, password reset) if you want a visible challenge as a last line of defence. Off by default.

= Form plugin compatibility =

Built-in adapters for:

* WordPress core comments, login, registration, password-reset
* Contact Form 7
* WPForms
* Gravity Forms
* Elementor Pro Forms
* WooCommerce checkout & registration
* Fluent Forms
* Ninja Forms
* Formidable Forms
* Forminator
* HTML Forms
* Jetpack Forms
* Bricks Builder forms
* Kadence Blocks forms
* Divi contact forms
* BuddyPress signup & activity
* bbPress topics & replies

Custom forms POSTing to `wp-admin/admin-post.php` or `wp-admin/admin-ajax.php` are picked up automatically by the generic adapter.

= The Vault =

Blocked submissions are stored encrypted for 30 days (configurable). Review them in the admin: see what was blocked, which page it was submitted from, and which inbox the notification was headed to. Mark false positives as legitimate and forward them by email with one click — the sender's address becomes the Reply-To, so answering in your mail client reaches the person who filled the form. Passed (legitimate) submissions are logged too, so you can audit both sides of every decision.

= Self-learning =

When you mark a Vault entry as "spam" the engine extracts the email domain / content phrase signatures and stores them in a learned-rules table with a score modifier. Future submissions matching those signatures get extra points, automatically. Auto-confirmed rules from repeat offenders are added too. Decay over time keeps the rule set fresh. Review, re-weight, deactivate or delete every learned rule from the Learned Rules screen.

= Privacy =

* The nine detection layers, the Vault and the self-learning system run entirely on your server. Two optional, off-by-default features talk to the outside: CAPTCHA verification (Cloudflare Turnstile / hCaptcha) and the DNS MX check — see "External services" below.
* IPs are stored only as `sha256(site_secret + "|" + ip)` and cannot be recovered.
* Vault payloads are encrypted at rest with AES-256-GCM (authenticated encryption).
* Uninstalling the plugin removes every option, every table and every cron event. Nothing is left behind.

== Installation ==

1. Upload the `formghost` folder to `wp-content/plugins/` (or install through the Plugins screen).
2. Activate FormGhost on the Plugins screen.
3. Run the one-time wizard that appears on activation — toggle the surfaces to protect and pick a sensitivity profile; FormGhost presets every layer.
4. Done. Real users keep submitting; bots stop arriving.

== Frequently Asked Questions ==

= Is FormGhost really completely free? =

Yes. All nine layers, the Vault, the self-learning system, Ghost Response — everything ships in the free plugin. There is no Pro tier and no license key.

= Will it break my real forms? =

No. FormGhost is invisible — no CAPTCHA, no extra fields visible to humans, no JavaScript prompts. The honeypot fields are hidden via multiple CSS techniques and `aria-hidden`. The timing token and proof-of-work fields are injected by JavaScript with no UI footprint.

= Does it work without JavaScript? =

The honeypot and email-content layers work without JavaScript. The timing and proof-of-work layers require JavaScript on the visitor's side; you can configure FormGhost to allow no-JS submissions (less strict) or to block them as suspect (stricter).

= Does it send data to your servers? =

No — FormGhost has no servers of its own and its spam detection never leaves your site. The only outbound calls the plugin can make are the optional, off-by-default Turnstile / hCaptcha token verification and the DNS MX lookup, both described under "External services" below.

= How does the wizard configure my site? =

Choose which surfaces to protect (comments, login, registration, contact forms, WooCommerce, password reset) and a sensitivity profile — Low, Medium or High. FormGhost applies a curated recipe of timing thresholds, proof-of-work difficulty and pattern aggressiveness. You can fine-tune everything afterwards in Settings, and re-run the wizard any time.

= I marked a legitimate submission as blocked. What now? =

Open the Vault, find the entry, click "Mark legitimate" — and click "Send" to forward it to the inbox it was originally headed to. The Learning system learns from your correction and lowers the weight of any rule that contributed to the false positive.

= Can I see what each layer did to a submission? =

Yes. The Vault detail view shows the score, the triggering layer, the reason code, the page the form was submitted from, and the notification recipient for every stored submission.

= Does it work with caching plugins? =

Yes. The honeypot CSS is inline, the timing token and PoW challenge are fetched at submission time via a cache-bypassed AJAX endpoint, and the Behavioral layer's nonce is also live-issued. Heavy page caching does not weaken FormGhost.

= Is it compatible with WP Rocket / W3 Total Cache / Cloudflare? =

Yes. None of the runtime fields are baked into the cached HTML. The plugin sends `nocache_headers()` on its own AJAX endpoint.

= Where are blocked submissions stored? =

In a `{prefix}formghost_vault` table you control, encrypted with AES-256-GCM against a per-site secret stored in `formghost_site_secret`. Default retention is 30 days; configurable; uninstall removes the table entirely.

= I run a forum / membership / e-commerce site — what do you recommend? =

Run the wizard once and enable the registration / WooCommerce scopes that match your attack surface, with the Medium sensitivity profile. Layers 4 (Behavioral), 5 (Rate limit) and 6 (Email) add the most uplift against modern bots and are on by default.

== Screenshots ==

1. The Dashboard — blocked and passed counts, layer breakdown, recent activity.
2. The Vault — review blocked submissions; see the source page and recipient; forward with one click.
3. Settings — choose exactly where FormGhost runs; every layer is tunable.
4. Learned Rules — see what the engine learned from your reviews.
5. The wp-admin dashboard widget — key numbers right after login.

== Changelog ==

= 1.2.4 =
* WordPress.org review: the release package no longer contains the directory artwork folder or other non-runtime files.
* Elementor Pro preflight now respects the master switch, the contact-form scope toggle, the IP whitelist and the `formghost/skip_form` filter, so a disabled FormGhost never intercepts an Elementor submission.
* Layer 9 CAPTCHA can now actually be switched on: new per-form toggles (comments, login, registration, password reset) and the widget container is printed on those core forms automatically.
* "Store passed submissions" now controls whether passed submissions are stored in the Vault (they are still counted when off).
* Programmatic settings saves (setup wizard) no longer reset developer-managed array settings.
* Uninstall also removes the per-user "items per page" screen options.
* Honeypot CSS is delivered once: the stylesheet WordPress prints in the page head now carries a marker, and the front-end script only injects its own copy when that stylesheet is missing.
* Documentation: FAQ and Privacy sections corrected (optional external calls, what learned rules can contain); stale development notes removed from code comments.

= 1.2.3 =
* WordPress.org review: the generic interceptor now classifies admin-ajax.php / admin-post.php requests via core's own signals (`wp_doing_ajax()`, `$pagenow`) instead of matching the request URI, so non-standard wp-admin locations work.
* WordPress.org review: settings tab selection now travels inside the Settings API's nonce-verified option input; the Contact Form 7 adapter no longer falls back to reading the raw request; the Elementor recipient resolver receives the validated page ID from the adapter instead of reading the request itself.
* WordPress.org review: POST field names in the Kadence and Divi adapters are sanitized before use; nested array values in the generic interceptor are recursively sanitized before scoring.
* Hardened Vault and Rules admin write paths: explicit capability check before any action, nonce checks untangled into standalone conditions, and row actions validated against a closed list. Rules row-action nonces are now bound to the individual rule ID.
* Token issuance (timing token, proof-of-work challenge, behavior nonce, ALTCHA challenge) is now fully stateless — HMAC-signed with the expiry embedded — so anonymous bootstrap requests write nothing to the database; single-use markers are written only when a token is actually consumed by a submission.
* When "behind reverse proxy" mode is enabled, the client IP is now taken from the right-most public X-Forwarded-For hop (the one vouched for by the trusted proxy) instead of the left-most, which a client can spoof.
* Ghost Response success messages are sanitized at the source and HTML-escaped in every per-plugin JSON envelope.
* The version constant is a literal instead of re-parsing the plugin header on every request.

= 1.2.2 =
* WordPress.org review: removed leftover cleanup code from the pre-1.1 licensing system and the retired Ghost Network source; the plugin contains no gating code of any kind — every feature is free.
* Inline `<style>` blocks (dashboard widget, honeypot) moved to enqueued stylesheets.
* Translations now come from translate.wordpress.org language packs; the bundled compiled files and the `load_plugin_textdomain()` call were removed.
* readme: full "External services" disclosure for the optional Turnstile / hCaptcha verification calls and the optional DNS MX lookup.
* Improved: marking a Vault entry as spam is now decisive — the sender's exact address (+50) and hashed IP (+30) are learned alongside the content signals, so the next message from that sender is ghosted; marking as legitimate (-50 on the address) guarantees a wrongly held sender passes. Learned rules now also apply to submissions without free text.

= 1.2.1 =
* Fixed: Contact Form 7 submissions arrive through the REST API, where the timing, proof-of-work and behavior layers and the bot preflight were skipped — only the honeypot and content patterns judged them. They now run for CF7 exactly as for a page POST. New filter `formghost/engine/rest_browser_form_types` for other JS-driven REST forms.
* New: cross-layer check — a submission that passed the timing or proof-of-work check but carries no behavior data (which the tracker injects into every form) is scored as a bot (`missing_after_js`).
* New: identity-churn detection — one email address submitting under changing names, or one IP sending as many different people, within seven days. The Vault stores keyed hashes only (never the address). Toggle under Layer 5.
* New: the Learning layer now tracks the full sender address as a rule type ("Email address"), so a mailbox reused by a bot escalates as a repeat offender even on gmail.com / mail.ru.
* Improved: content patterns learn lead-generation, "website traffic", directory-listing, newsletter-bombing and advance-fee scam vocabulary; new structural signals — unsubscribe boilerplate, a third-party link carrying this site's own domain, "Hello <Domain> Owner" greetings, repeated links, emoji bait, throwaway hosting (vercel.app, netlify.app, workers.dev, …) and 19 more URL shorteners, matched by host.

= 1.2.0 =
* New: adapters for six more form plugins — Forminator, HTML Forms, Jetpack Forms, Bricks Builder, Kadence Blocks, and Divi contact forms.
* New: complete Arabic translation, with right-to-left admin support.

= 1.1.0 =
* Everything is free: all nine layers, self-learning, Learned Rules screen and Ghost Response now ship free of charge. The former activation screen was removed.
* New: "Passed" card on the dashboard — see the submissions that were NOT blocked and click through to review them.
* New: FormGhost widget on the main wp-admin dashboard with blocked/passed counts and quick links.
* New: dashboard stat cards link into the filtered Vault views.
* Improved: "Blocked today" now follows the site's timezone instead of UTC.
* Improved: ghost-response counting is exact — it no longer under-counts when ghost logging is off or entries are reviewed/purged.
* Improved: email domains in the Vault are shown in full, and the search box matches partial domains.
* Improved: the IP whitelist now honours CIDR ranges in every layer, including the engine's early skip.
* Improved: Vault filters cover every supported form plugin (Fluent, Ninja, Formidable, BuddyPress, bbPress, custom forms, password reset).
* Fixed: default settings are now merged on front-end requests too, so a partially saved settings option can never silently disable a layer.
* Fixed: the "Protect contact-form plugins" toggle now also covers custom forms caught by the generic interceptor.

= 1.0.0 =
* Initial public release.

== Upgrade Notice ==

= 1.1.0 =
All features are now free. New passed-submissions view and wp-admin dashboard widget.

== External services ==

FormGhost's spam detection runs entirely on your own server. Two optional features, both **off by default**, connect to third parties. Nothing is sent unless you enable them in the settings.

**Cloudflare Turnstile** (Layer 9, optional CAPTCHA provider)
When you enable the CAPTCHA layer with Turnstile for a form, the plugin renders the widget container on that form (you add Cloudflare's widget script `https://challenges.cloudflare.com/turnstile/v0/api.js` to your site yourself — the plugin does not load any vendor script), and on every submission of that form the plugin sends the widget's response token, your Turnstile secret key and the visitor's IP address to `https://challenges.cloudflare.com/turnstile/v0/siteverify` to verify the challenge.
Terms: https://www.cloudflare.com/terms/ — Privacy: https://www.cloudflare.com/privacypolicy/

**hCaptcha** (Layer 9, optional CAPTCHA provider)
When you enable the CAPTCHA layer with hCaptcha for a form, the plugin renders the widget container on that form (you add hCaptcha's widget script `https://js.hcaptcha.com/1/api.js` to your site yourself — the plugin does not load any vendor script), and on every submission of that form the plugin sends the widget's response token, your hCaptcha secret key and the visitor's IP address to `https://api.hcaptcha.com/siteverify` to verify the challenge.
Terms: https://www.hcaptcha.com/terms — Privacy: https://www.hcaptcha.com/privacy

**ALTCHA** (Layer 9, optional CAPTCHA provider) is self-hosted: the challenge endpoint and the verification run on your server (`admin-ajax.php?action=formghost_altcha_challenge`); no data is sent anywhere. You add the ALTCHA widget script to your site yourself.

**DNS MX lookup** (Layer 6, optional "Check MX records" setting)
When enabled, the plugin asks your server's DNS resolver for the MX records of the submitted email address's domain (PHP `getmxrr`). This is a standard DNS query from your server, not a request to a third-party API; the email address itself is not transmitted, only its domain.

== Privacy ==

FormGhost is designed for privacy-conscious operators.

**Data stored on your server.**

* `{prefix}formghost_vault` — encrypted form payloads of blocked / passed submissions plus `sha256(IP + site_secret)` and `sha256(User-Agent + site_secret)` hashes. AES-256-GCM authenticated encryption keyed off the per-site secret. Configurable retention (default 30 days). Removed on uninstall.
* `{prefix}formghost_learned_rules` — score modifiers learned from admin review and auto-confirmation. A rule may hold the sender email address of a submission you reviewed, or an IP stored only as `sha256(IP + site_secret)`. Rules decay when stale and can be deleted from the Learned Rules screen. Removed on uninstall.
* `{prefix}formghost_log` — block / pass counters per layer per form type for the dashboard. No PII. Removed on uninstall.
* `formghost_site_secret` (option) — 64-char random secret used for IP / UA hashing, payload encryption and CSS class derivation. Removed on uninstall.

**Data sent off your server.** None by default. Only the optional services listed under "External services" send anything, and only after you enable them.

**Cookies.** FormGhost does not set cookies.

For full source, audit, and integration docs, see https://byabdalla.com/lab/formghost.
