Plugin Version: 1.0.2+
Requires: WordPress 5.8+, PHP 7.4+
Settings Location: WordPress Admin → Settings → HashCash

Captcha - HashCash for WordPress on RicheyWeb.com | Captcha – HashCash on WordPress.org

For Site Owners

Installation

  1. Download the plugin from WordPress.org or upload the captcha-hashcash folder to /wp-content/plugins/
  2. Activate through Plugins → Installed Plugins
  3. Go to Settings → HashCash to review configuration
  4. Done — all supported forms are protected immediately

No API keys. No account required. No third-party setup.

Settings Reference

Navigate to Settings → HashCash to access all configuration options.

Maximum Form Lifetime

Default: 1800 (30 minutes)
Range: 300–3600 seconds

How long a completed proof-of-work remains valid. When a user loads a form, HashCash begins calculating in the background. The result is timestamped. On submission, the server checks that the timestamp is within this window of the current time.

This prevents replay attacks — where a bot captures a valid proof-of-work solution and reuses it repeatedly. A solution that’s more than 30 minutes old is rejected regardless of whether it’s mathematically valid.

HashCash automatically refreshes the calculation before it expires, so users who leave a form open for extended periods won’t encounter submission errors.

When to change this: The default is appropriate for most sites. Reduce it (to 300–600 seconds) on high-security forms like login or registration. Increase it only if your users frequently take longer than 30 minutes to complete a form.

Difficulty Level

Default: 1
Range: 1–12 (3–5 recommended for SHA-based algorithms)

Controls how hard the proof-of-work calculation is. Higher levels require more computation, which means stronger bot protection but longer solve times for users.

For SHA-based algorithms:

Level Security Approximate Solve Time Notes
1 Low ~3ms Near-instant. Deters simple bots only.
2 Low ~35ms Imperceptible to users.
3 Medium ~212ms Comfortable for most sites.
4 Medium ~4.6s Noticeable pause. Stops most automated abuse.
5 High ~26s Very long. Consider PBKDF2+64K at lower levels instead.

For Argon2id: Keep difficulty at 1. Security with Argon2id is controlled entirely by the Memory, Iterations, and Parallelism parameters — not the difficulty level. Level 2 with Argon2id takes over a minute on modern hardware and is not usable.

Hash Algorithm

Default: SHA-256

Selects the cryptographic algorithm used for proof-of-work calculation. Each option represents a different balance of compatibility, speed, and bot resistance.

SeeWhich Algorithm Should I Use? for a full comparison.

⚠️ iOS Device Compatibility Note: All iPhones and iPads use Apple’s WebKit browser engine regardless of which browser icon the user taps. HashCash requires iPhone 11 (2019) or newer for full algorithm support. Older iOS devices may experience slow or incomplete hash calculations. If your audience includes users on older iPhones, SHA-256 or SHA-384 at low difficulty levels are the safest choices.

Argon2id Parameters

Visible only when Argon2id is selected as the Hash Algorithm

Argon2id’s strength comes from three parameters that control how much memory and CPU time each calculation requires. Unlike SHA-based algorithms, difficulty level has minimal effect on Argon2id — security is controlled here instead.

Memory (KiB)
Default: 16384 (16 MB) | Recommended starting point: 65536 (64 MB)

RAM required per calculation attempt. Higher values make GPU and ASIC attacks impractical — each parallel attempt needs dedicated RAM, which limits how many a bot farm can run simultaneously.

Iterations
Default: 2 | Recommended starting point: 3

Number of passes over the allocated memory. Increases CPU cost without requiring more RAM. Raise this if you want more computational cost without increasing memory requirements.

Parallelism
Default: 1

Number of parallel threads used per calculation. Should remain at 1 for web form protection — increasing this primarily benefits password storage scenarios, not CAPTCHA use cases.

Recommended starting configuration: Memory 65536 / Iterations 3 / Parallelism 1. Adjust from there based on observed solve times on your target devices.

Behavior Options

Delay mining until form interaction (recommended)
Default: Enabled

HashCash waits for real user interaction — a mouse movement, keypress, or click — before starting the proof-of-work calculation. This blocks bots that submit forms instantly without any interaction, and bots that load the page and wait without doing anything.

Disabling this starts the calculation immediately on page load. Not recommended — it removes a significant layer of bot detection.

Punish suspicious bots (solution becomes impossible)
Default: Enabled

When suspicious behavior is detected, HashCash sets the difficulty to a level that is computationally unsolvable. The bot’s browser spins indefinitely attempting a calculation it can never complete. Legitimate users are completely unaffected.

Without this enabled, detected bots are simply ignored — the form remains submittable. Punishment mode is more aggressive and more effective.

Enable CDP / DevTools detection
Default: Enabled

Detects Chrome DevTools Protocol (CDP) automation — the technology used by headless browsers like Puppeteer and Playwright to automate web interactions. When CDP signatures are found in the browser runtime, the request is treated as suspicious.

Enable nonce field (extra bot protection)
Default: Enabled

Adds a hidden field with a randomly generated value that legitimate browsers handle correctly and automated submissions typically don’t. Provides an additional signal for bot detection without any user-facing impact.

Advanced Options

Trigger custom event on bot detection
Default: Disabled

When enabled, HashCash fires a JavaScript custom event (plg_captcha_hashcash) on the window object when suspicious behavior is detected. Intended for developers who want to integrate HashCash’s bot detection signals into custom logging, analytics, or security workflows.

See JavaScript Eventsfor event details.

Which Algorithm Should I Use?

Algorithm GPU Resistance iOS Support Best For
SHA-256 Low Full Default — maximum compatibility
SHA-384 Low Full Light upgrade, same compatibility
SHA-512 Low–Medium Full Blog comments, public forms
PBKDF2 Medium Full Enhanced protection without memory cost
PBKDF2 (64KB) High Full High-traffic targets, aggressive bots
Argon2id Maximum iPhone 11+ only Financial, medical, high-value targets

Start with SHA-256 at difficulty 3. It’s fast, universally compatible, and stops the vast majority of spam bots. Most sites never need anything stronger.

Step up to PBKDF2 or PBKDF2+64KB if you’re seeing sophisticated bot traffic that gets through SHA-based protection, or if your forms are high-value targets.

Use Argon2id if you’re protecting financial systems, medical records, or any environment where well-resourced attackers with GPU farms are a realistic threat. Check your analytics for iOS device share before enabling — older iPhones are not fully supported.

Supported Forms

The following forms are protected automatically — no configuration required. Protection applies to non-logged-in users only. Logged-in users are exempt from all HashCash verification.

Form Protection Method
WordPress comment form Automatic
WordPress login form Automatic
WordPress registration form Automatic
WordPress lost password form Automatic
Contact Form 7 Automatic
Any other HTML form use shortcode

What Users See

When a user loads a protected form, HashCash begins calculating in the background. While the calculation runs, a brief indicator appears:

⟳ Securing this form…

The submit button is disabled during this time. When the calculation completes — typically within seconds at default settings — the indicator disappears and the submit button re-enables. The user can then submit normally.

There is nothing for the user to click, solve, or interact with. The indicator is feedback, not a challenge.

Troubleshooting

“There was an error trying to send your message” in Contact Form 7
This is a mail delivery error, not a HashCash error. If invalid_fields is empty in the CF7 response, HashCash validated successfully. Check your WordPress mail configuration (WP Mail SMTP or similar).

Form submits but HashCash validation fails
Check that your server’s system clock is accurate. HashCash compares the proof-of-work timestamp against the current server time — significant clock drift will cause validation failures.

Solve time is very long for legitimate users
Reduce difficulty level or switch to a less intensive algorithm. At SHA-256 difficulty 3, solve time should be under 250ms on any modern device.

Older iPhones are having trouble
Switch to SHA-256 or SHA-384 at difficulty 1–2. All iPhones use WebKit regardless of browser — iPhone 11 (2019) or newer is required for full algorithm support.

CF7 field not appearing
Ensure HashCash is activated. CF7 support is automatic but requires both plugins to be active. If the field still doesn’t appear, try deactivating and reactivating HashCash.

Emergency Recovery

If a misconfiguration makes your login form unsolvable and you can’t access the WordPress admin:

  1. Open wp-config.php in a text editor (via FTP, cPanel File Manager, or SSH)
  2. Add this line before the /* That's all, stop editing! */ line:
    define('CAPTCHA_HASHCASH_OVERRIDE', true);
  3. Save the file
  4. Log in to WordPress normally — HashCash verification is now bypassed site-wide
  5. Go to Settings → HashCash and fix the configuration
  6. Remove the line you added from wp-config.php
  7. Save the file

⚠️ Important: Remove the override constant immediately after fixing your settings. Leaving it in place disables HashCash protection entirely.

For Developers

Adding HashCash to Custom Forms

For any form not automatically supported, use the shortcode.

[hashcash]

Or call the static method directly in PHP:

HashCash::field(); // Echoes the field directly
$field = HashCash::field(false); // Returns the field as a string

The field renders a hidden input and the “Securing this form…” indicator. Ensure the form has a submit button with type="submit" — HashCash disables it during calculation and re-enables it on completion.

Minimum required form structure:

<form method="post">
    <!-- your fields -->
    [hashcash]
    <button type="submit">Submit</button>
</form> 

Available Hooks and Filters

wpcf7_form_elements

HashCash uses this filter to automatically inject the proof-of-work field into Contact Form 7 forms. If you need to prevent automatic injection for a specific form, you can remove the filter:

remove_filter('wpcf7_form_elements', [$hashcash_instance, 'cf7_add_hashcash_field']);

wpcf7_spam

HashCash validates CF7 submissions via this filter at priority 10. To adjust priority relative to other spam filters:

remove_filter('wpcf7_spam', [$hashcash_instance, 'cf7_validate_spam'], 10);
add_filter('wpcf7_spam', [$hashcash_instance, 'cf7_validate_spam'], 20); // run later

preprocess_comment

Comment validation runs at priority 1. HashCash calls wp_die() on failure — if you need softer handling, remove this filter and implement your own validation using HashCash::check_answer().

JavaScript Events

HashCash fires custom events on the form element during the proof-of-work lifecycle. Use these to build custom UI or integrate with analytics.

plg_captcha_hashcash_started
Fired when proof-of-work calculation begins.

form.addEventListener('plg_captcha_hashcash_started', () => {
    console.log('Mining started');
});

plg_captcha_hashcash_finished
Fired when proof-of-work calculation completes successfully.

form.addEventListener('plg_captcha_hashcash_finished', () => {
    console.log('Mining complete');
});

plg_captcha_hashcash_progress
Fired every 1,000 iterations during calculation. The event detail includes the current iteration count.

form.addEventListener('plg_captcha_hashcash_progress', (e) => {
    console.log('Iterations completed:', e.detail.count);
});

plg_captcha_hashcash (window event)
Fired on the window object when bot detection is triggered. Only fires when “Trigger custom event on bot detection” is enabled in settings.

window.addEventListener('plg_captcha_hashcash', (e) => {
    console.log('Bot detection triggered', e.detail);
});

The Bypass Constant

HashCash checks for a constant defined in wp-config.php that allows site-wide bypass of all verification. This is intended for emergency recovery and local development environments.

// In wp-config.php:
define('CAPTCHA_HASHCASH_OVERRIDE', true);  // Bypass all verification
define('CAPTCHA_HASHCASH_OVERRIDE', false); // Normal operation (same as not defining it)

If CAPTCHA_HASHCASH_OVERRIDE is not defined, HashCash operates normally.

Do not leave this set to true in production. It disables all spam protection.

Algorithm Technical Reference

SHA-256 / SHA-384 / SHA-512

Standard SHA-2 variants implemented via the browser’s Web Cryptography API (SubtleCrypto). Fast, universally supported, zero memory overhead. Vulnerable to GPU parallelization at higher difficulty levels — a GPU can attempt many hashes simultaneously, reducing effective difficulty. Appropriate for most sites at levels 1–3.

PBKDF2

Password-Based Key Derivation Function 2, implemented via SubtleCrypto.deriveBits(). Adds 1,000 iterations of SHA-256 per attempt, increasing CPU cost without significant memory overhead. Provides moderate GPU resistance. Salt: WordPressHashCashSalt.

PBKDF2 (64KB)

PBKDF2 with a memory-hard extension — 15,000 iterations with a dynamically derived salt (SHA-256 of the input). Pushes GPU solve times into the 8–18 second range while keeping legitimate user solve times under 3 seconds. Appropriate for high-traffic targets facing sophisticated bot attacks.

Argon2id

Winner of the Password Hashing Competition (2015). Memory-hard by design — each attempt requires the full configured memory allocation, making parallel GPU/ASIC attacks expensive regardless of hardware budget. Implemented via WebAssembly (argon2.umd.min.js) in the browser worker, and via PHP’s sodium_crypto_pwhash() on the server.

Salt: WordPressHashCashSalt (fixed, 16 bytes)
Output: 32-byte hash, hex-encoded
Server requirement: PHP sodium extension (available by default in PHP 7.2+)
iOS requirement: iPhone 11 (2019) or newer

Argon2id parameter guidance:

Parameter Default Effect of Increasing
Memory (KiB) 16384 Raises RAM cost per attempt — primary GPU defense
Iterations 2 Raises CPU cost without more RAM
Parallelism 1 Minimal effect for CAPTCHA use cases — leave at 1

OWASP minimum recommendation for Argon2id: Memory 19456 KiB / Iterations 2 / Parallelism 1. HashCash default (16384/2/1) is slightly below this — consider raising memory to 19456 or higher for security-sensitive deployments.

Proof-of-Work Verification

Server-side verification reconstructs the hash using the submitted iteration count and compares it against the difficulty pattern. The verification string is: {client_ip}{timestamp}{iteration_count}. The server checks that the resulting hash begins with the required number of leading zeros (SHA-based) or matches the Argon2id output pattern.

Timestamp validation window: ±60 seconds future, maximum max_age seconds past. This prevents both future-dated submissions and replay attacks.

Why is this software free?

I’m ditching the freemium game and giving this software to the Joomla crowd for free. It’s a nod to “Jumla”—Swahili for “all together”—because fragmentation sucks, and I’d rather focus on innovation and paid gigs. Use it, build with it, and if you need custom work, I’m super into that.

What's The Catch?

There isn’t one! I’m all about building tools that empower the Joomla community and spark creativity. This software’s free because I’d rather see it in your hands - fueling awesome projects. If you really feel like paying something, I’d appreciate a review in the Joomla Extension Directory—your feedback means a lot!