Releases: WebDecoy/FCaptcha
v1.6.0 - Signal Commitment & Security Hardening
Security Hardening
This release closes the attack vector where an attacker could solve proof-of-work legitimately then fabricate all behavioral signals to score 0.00.
Signal Commitment via PoW Binding
- Client collects signals before solving PoW, hashes them (SHA-256), and embeds the hash into the PoW input
- Server verifies
SHA256(signalsJson) == powSolution.signalsHash— signals can no longer be tampered after PoW is solved signalsJsonsent alongsidesignalsfor deterministic cross-language hash verification
Challenge-Response Nonce
- Server generates a random nonce per challenge
- Client echoes it in
signals.meta.challengeNonce - Server verifies match to prevent replay of old signal sets with new PoW solutions
Full 256-bit HMAC Signatures
- Removed all HMAC truncation (
.slice(0,16)/[:16]) across Node.js, Python, and Go servers - Signatures now use full 256-bit HMAC-SHA256 instead of brute-forceable 64-bit
Protocol Changes
- New PoW hash format:
SHA256(prefix + ':' + signalsHash + ':' + nonce) - New request fields:
signalsJson,powTiming(separate from committed signals) - Client defers PoW solving until after signal collection (was: solve eagerly on page load)
- Zero UX impact — all changes are internal to the client/server protocol
Applied consistently across all three server implementations (Node.js, Python, Go).
v1.5.0 - Mobile verification fix
Fixes
- Fix mobile verification failing —
_getEmptyAnalysis()in the client hardcodedtouchEvents: 0instead of using the actual count. On mobile (no mouse events), this path always ran, so the server never saw touch data and flagged users as bots. - Lower touch exemption threshold — Server required
touchEvents >= 3but a single tap only produces 1–2 events. Lowered to>= 1across Go, Node.js, and Python servers.
Other
- Remove Docker Hub publishing, keep GHCR only
Docker
docker pull ghcr.io/webdecoy/fcaptcha:1.5.0
docker pull ghcr.io/webdecoy/fcaptcha:latest
v1.4.1 - Multi-Platform Publishing & Deploy Buttons
What's New
Docker Hub Support
The CI workflow now publishes to Docker Hub in addition to GHCR:
docker pull webdecoy/fcaptchaTo enable: add DOCKERHUB_USERNAME (repository variable) and DOCKERHUB_TOKEN (repository secret) in GitHub settings.
One-Click Deploy Buttons
Deploy FCaptcha with a single click on:
- Render —
render.yamlblueprint included - Railway — deploy button in README
- Fly.io —
fly.tomlincluded, justfly launch --copy-config
Artifact Hub
Added artifacthub-repo.yml for listing on Artifact Hub.
Changes
- Workflow pushes to both GHCR and Docker Hub (Docker Hub gated on
DOCKERHUB_USERNAMEvariable) - Added
render.yamlfor Render one-click deploy - Added
fly.tomlfor Fly.io deploy - Added
artifacthub-repo.ymlfor CNCF Artifact Hub listing - Added deploy buttons and Docker Hub badge to README
v1.4.0 - Docker Image & One-Command Deploy
What's New
Pre-built Docker Image
FCaptcha is now available as a pre-built Docker image on GitHub Container Registry:
docker run -d -p 3000:3000 -e FCAPTCHA_SECRET=my-secret ghcr.io/webdecoy/fcaptchaMulti-platform support: linux/amd64 and linux/arm64 (x86 servers + AWS Graviton / Apple Silicon).
Static File Serving
The Docker image bundles everything you need:
- API at
/api/* - Client JS at
/fcaptcha.js - Demo page at
/demo/ - Health check at
/health
Docker Compose with Redis
FCAPTCHA_SECRET=my-secret docker compose -f docker/docker-compose.yml up -dChanges
- Add static file serving routes to Go server (
/fcaptcha.js,/demo/*) - Fix Dockerfile broken paths (
server/→server-go/) - Bundle demo page in Docker image with patched same-origin paths
- Add
image: ghcr.io/webdecoy/fcaptcha:latestto docker-compose.yml - Add GitHub Actions workflow for automatic GHCR publish on release
- Add
.dockerignorefor clean builds - Update README with Docker-first quick start
v1.3.0 - Keystroke Cadence Analysis
What's New
Keystroke Cadence Analysis (7 Biometric Metrics)
Adds deep statistical analysis of keystroke timing to detect sophisticated bots that add timing jitter — something FCaptcha's existing rhythm checks miss.
7 metrics analyzed:
- Dwell Variance — key hold duration consistency
- Log-Normal Fit — KS test of interval distribution against expected human log-normal
- Uniformity Detection — catches
Math.random()jitter bots - Lag-1 Autocorrelation — sequential timing dependency (humans have natural patterns)
- Burst Regularity — variation in pause gaps between typing bursts
- Shannon Entropy — information content of interval distribution
- Rollover Rate — overlapping keypresses (natural in fast typists)
False Positive Prevention
- Gated on minimum data: requires 20+ keystrokes and 15+ intervals
- Conservative composite threshold: requires multiple metrics to agree (botScore > 0.55)
- Score scaled down (×0.7) to prevent dominating overall detection
- Slow typists, hunt-and-peck, fast typists, and keyboard-only users all pass safely
Changes
- Client: Extended FormAnalyzer to collect dwell times, rollovers, and raw intervals per textarea
- All servers (Node.js, Python, Go): Added statistical utility functions and
analyzeKeystrokeCadence()called fromanalyzeFormInteraction() - Tests: 4 new test cases (human cadence, constant-timing bot, alternating-jitter bot, minimal data)
v1.2.1 - Playwright Bot Detection & PoW Hardening
What's Changed
Security Fixes
- Server-side challenge timing: Detects instant PoW solves using un-spoofable server timestamps (
serverElapsed < 1500ms→ flagged) - PoW now mandatory: Missing PoW solution triggers hard-fail (score 0.9, confidence 0.95) — previously only scored 0.5/0.6
- Tightened accessibility exemptions:
touchEvents >= 3(was> 0) andkeyEvents >= 2(was> 0) to prevent trivial spoofing
New Detection
- Playwright-specific client detection: New
_detectPlaywright()checks for__pw*/__playwright*globals, deleted/configurablewebdriverproperty, and missingchrome.runtime - Server-side Playwright scoring:
playwright_globals(0.95),webdriver_deleted(0.8),webdriver_configurable(0.7),chrome_runtime_missing(0.6)
Go Server
- Wired up
/api/pow/challengeendpoint (was missing) VerifyWithHeaders()now accepts and processes PoW solutions- Fixed pre-existing missing
fmtimport indetection.go
Weight Rebalancing
| Category | Before | After |
|---|---|---|
| bot | 0.10 | 0.15 |
| rate_limit | 0.05 | 0.01 |
| tor_vpn | 0.02 | 0.01 |
Tests
- 9 new tests (69 total, all passing)
- Covers: Playwright detection, missing PoW hard-fail, tightened touch/keyboard exemptions
Full Changelog: v1.2.0...v1.2.1
v1.2.0 - AI Agent Bypass Fix
What's Changed
Security Fix
- Fixed AI agent bypass vulnerability — AI agents like Manus could bypass FCaptcha by clicking the checkbox with zero mouse movement. All behavioral detection checks required minimum trajectory lengths to trigger, so zero-movement clicks passed silently.
New Detections
- Zero mouse movement now flagged as high-confidence bot signal (score 0.9) in both
detectVisionAIanddetectBehavioral - Missing approach trajectory to target flagged (score 0.7)
- Insufficient mouse movement (< 10 points, < 30px trajectory) flagged (score 0.6)
Accessibility
- Touch users (mobile) are exempt from mouse-movement checks — taps don't generate mouse events
- Keyboard-only users (screen readers, accessibility) are exempt — Tab+Enter navigation is valid
- Added
touchstartlistener to checkbox widget (was only listening fortouchmove, which missed simple taps)
Bug Fixes
- Fixed detection weights summing to 1.10 instead of 1.0
- Fixed duplicate variable declarations in Go server
All Changes
- Applied consistently across all 3 server implementations (Node.js, Python, Go) and client-side fallback
- Updated test suite with realistic behavioral data
- All 58 tests passing
v1.1.0 - Advanced Fingerprint Detection
Added advanced fingerprint detection for improved bot detection
v1.0.4
Full Changelog: v1.0.3...v1.0.4