Install
This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.
Install straight from GitHub with WP-CLI:
wp plugin install https://github.com/astheysaymehrab/persian-captcha/archive/refs/heads/main.zipA self-hosted, accessible arithmetic CAPTCHA for WordPress, built for sites where external CAPTCHA providers may be blocked or unavailable. All assets and challenges are served by your own WordPress installation. No API keys, third-party requests, PHP sessions, cookies, Composer dependencies, JavaScript libraries, GD, or Imagick are required.
Status: release candidate. Implementation and test suites are included. PHP/WordPress integration tests must pass before public release; this development environment has no PHP runtime. The 1.0.0 package version does not imply a verified production release.
Maintained by AsTheySayMehrab. See PUBLISHING.md for GitHub setup, release artifacts, and WordPress.org submission.
Features
- Protects standard WordPress login,
wp_login_form(), registration, lost-password requests, and comments. - Persian and English questions, right-to-left layout, and Persian/Arabic/ASCII answer digits.
- Screen-reader labels, keyboard controls, visible focus, and locally served refresh button.
- Ten-minute HMAC-signed challenges bound to the site, form, and comment post.
- Atomic database replay protection: each authentic attempt consumes the challenge, including a wrong answer.
- 20 verification attempts per client IP, per form, per five-minute fixed window. Issuance is limited to 60 requests per IP per minute.
- Cached pages obtain fresh challenges through a no-store local AJAX endpoint. An uncached page can also work without JavaScript.
- Per-form switches and language selection under Settings → Persian Captcha.
- XML-RPC password authentication disabled by default, with an explicit setting to restore it.
- Scheduled cleanup and removal of settings, security records, and cron events on uninstall.
Install
Requires WordPress 6.5+ and PHP 7.4+ with the normal WordPress database. Use a currently supported PHP release for deployment.
- Build with
python scripts/build.py, or use the ZIP indist/. - In WordPress, open Plugins → Add New → Upload Plugin and upload
persian-captcha-1.0.0.zip. - Activate and review Settings → Persian Captcha.
- Keep your admin session open and test login in a private browser window, then registration, reset, and comments. Check the actual theme, caching configuration, and any membership plugins used on your site.
There are no runtime package installs or outgoing service requests. Development tools and CI dependencies are not shipped in the ZIP.
Scope and compatibility
This plugin deters basic spam and limits repeated interactive attempts. Arithmetic can be solved by advanced bots; this is not equivalent to Cloudflare Turnstile or a network firewall. It does not provide DDoS protection, browser reputation, breached-password checks, or two-factor authentication.
Native WordPress forms are integrated automatically. Custom browser password logins are also validated, so their forms need a field: put [persian_captcha] inside a custom login form. This shortcode renders a login challenge; it does not create a form. Do not add it to a form that already contains the plugin's field. Third-party forms that bypass core validation hooks need a dedicated integration; WooCommerce, membership plugins, and contact forms are not claimed as supported. Disable the affected switch until that integration is tested.
REST application-password authentication and WP-CLI are outside the interactive login check. Public REST comments, pingbacks, and trackbacks are rejected while comment protection is enabled because they do not carry a valid interactive answer. Authenticated comment moderators and WP-CLI comment operations are exempt. Standard browser comments from other signed-in users are protected. Password reset protection covers the request for a reset email, not the password selection form reached through the secret reset link.
Multisite supports activation separately on each site. Network activation and network-wide signup at wp-signup.php are not supported. Do not describe this release as protecting multisite signup.
The rate limiter uses REMOTE_ADDR; forwarded headers are intentionally not trusted. Behind a reverse proxy, configure the web server to restore the client IP only from trusted proxies. Shared networks share limits. Fixed windows permit a burst across a window boundary; these are basic application-level limits, not an edge firewall.
JavaScript enhances cached pages by obtaining a new challenge from wp-admin/admin-ajax.php. Do not cache or block this endpoint. If JavaScript is disabled, exclude protected pages from full-page caching; refresh an uncached page after an error or after ten minutes. Refresh failures keep the form blocked and show a retry message. A database outage also fails closed. A site with multiple web servers must share the same database and WordPress salts.
Privacy and storage
No telemetry, remote fonts, external scripts, third-party cookies, or external requests. The plugin stores random used-token identifiers with expiry times and keyed IP-derived identifiers with counters. It does not store answers, usernames, raw IP addresses, passwords, or user-agent strings. IP-derived identifiers are still pseudonymous data, not a claim of legal anonymity. Records are removed by hourly WP-Cron; cleanup can be delayed on low-traffic sites or when WP-Cron is disabled. Configure a system cron to run WordPress scheduled events in that case. Deactivation preserves settings and records; deletion removes them.
Lockout recovery
Keep an authenticated admin session while testing. To recover, deactivate with wp plugin deactivate persian-captcha, or rename wp-content/plugins/persian-captcha using your hosting file manager. No third-party recovery service is needed.
Development and validation
For an isolated local WordPress installation, see LOCAL-TESTING.md. The setup script requires Docker Desktop with Linux containers.
php tests/challenge.php
node --check assets/captcha.js
node tests/frontend.mjs
python scripts/build.py
Optional browser checks use Playwright (development only): npm install --no-save playwright@1.56.1, npx playwright install chromium, then node tests/browser.mjs. PLAYWRIGHT_MODULE can point to an existing module and CHROME_PATH to an installed Chrome executable.
GitHub Actions includes PHP 7.4/8.3/8.4 checks; disposable MySQL-backed WordPress 6.5/latest integration tests against the install ZIP; actual HTTP login, reset, and comment tests; browser checks; Plugin Check; and uninstall verification. tests/wordpress.php, tests/http.py, and tests/uninstall.php are only for disposable test sites. CI has not run until this repository is pushed to GitHub. The manual release-artifact workflow requires passing tests and complete publication metadata.
See VALIDATION.md for the checks completed in this workspace, RELEASE.md for the publication checklist, and SECURITY.md for the threat model. Licensed under GPL-2.0-or-later; the full GPL v2 text is in LICENSE.