A performant proof-of-work captcha system that uses no JavaScript for its core verification logic, leveraging the fact that CSS animations and HTML are turing complete.
XCaptcha (Xcluding JavaScript Captcha) demonstrates that modern browsers can perform proof-of-work verification using only CSS and HTML, without requiring JavaScript execution. This provides several benefits:
- No JavaScript Required: Works even when JavaScript is disabled
- Bot Resistance: Forces bots to perform computationally intensive rendering work
- Privacy Friendly: No tracking scripts or fingerprinting
- Universal: Works on any modern browser
- Challenge Generation: Server generates a unique challenge with timestamp, nonce, and HMAC signature
- CSS Computation: Browser runs computationally intensive CSS animations (rotations, filters, transforms) for a configured number of iterations
- Proof of Work: CSS animations perform GPU-intensive operations that cannot be skipped
- Verification: Server validates the challenge signature and timestamp freshness
The core innovation uses CSS animations with:
/* GPU-intensive proof-of-work using CSS custom properties */
.xcaptcha-widget {
--xcaptcha-duration: 3s;
--xcaptcha-steps: 600;
}
/* Primary animation layer with expensive filters/transforms */
.xcaptcha-work {
animation: xcaptcha-pow-1 var(--xcaptcha-duration) steps(var(--xcaptcha-steps)) forwards;
}
@keyframes xcaptcha-pow-1 {
0% {
filter: blur(0px) contrast(100%) saturate(100%);
transform: perspective(1000px) rotateX(0deg) rotateY(0deg);
}
/* Multiple expensive filter/transform operations per step */
100% {
filter: blur(45px) contrast(450%) saturate(450%);
transform: perspective(1000px) rotateX(75deg) rotateY(0deg);
}
}Key techniques:
- Checkbox Hack: Uses hidden checkboxes with labels to create state machines
- Animation Delays: Progress bars and completion triggers use animation duration as time locks
- Multiple Layers: Concurrent animations multiply computational cost
- GPU Intensive Operations: Uses
filter,transform, andbox-shadowwhich require GPU computation
# Clone or download the repository
git clone <repository-url>
cd xcaptcha
# Install dependencies
pip install -r requirements.txt
# Run the server
python server.pyAccess the demo at: http://localhost:5000
The demo page (demo/index.html) is automatically generated from the widget template (xcaptcha/widget.html). This ensures consistency - you only need to update the widget!
To regenerate the demo after editing the widget:
python build.pyOr make it executable once:
chmod +x build.py
./build.pyWorkflow:
- Edit
xcaptcha/widget.htmlwith your changes - Run
python build.pyto regeneratedemo/index.html - Test the demo to verify your changes
The build script extracts the CSS and HTML from the widget and injects it into the demo template.
Edit server.py to adjust difficulty:
WORK_DIFFICULTY_ITERATIONS = 10000 # Number of CSS animation iterations
CHALLENGE_TIMEOUT = 300 # Challenge expires after 5 minutes┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Client │ │ CSS Engine │ │ Server │
│ (Browser) │────▶│ (GPU/CPU) │ │ (Python) │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│ │ │
│ 1. Request Form │ │
│──────────────────────▶│ │
│ │ │
│ 2. Return Challenge │ │
│◀──────────────────────│ │
│ │ │
│ 3. Start Animation │ │
│──────────────────────▶│ │
│ │ 4. Render 10000+ iters │
│ │ (computational work) │
│ │ │
│ 5. Enable Submit │ │
│◀──────────────────────│ │
│ │ │
│ 6. POST Form + Proof │ │
│────────────────────────────────────────────────▶│
│ │ │ 7. Verify
│ │ │ Signature + Time
│ 8. Success/Failure │ │
│◀────────────────────────────────────────────────│
Modern CSS supports:
- State Machines: Using the
:checkedpseudo-class with checkbox inputs - Loops: Via
animation-iteration-count - Conditionals: Via sibling selectors (
~,+) - Variables: CSS custom properties (variables)
- Calculations:
calc()function
Each animation frame requires:
- Layout calculation: Transform matrices
- Paint operations: Filter effects (blur, contrast, saturate)
- Composite layers: GPU texture operations
- Style recalculation: Box-shadow and color changes
Running 10000+ iterations of complex transforms and filters forces the browser's rendering engine to perform significant computation.
The CSS animation system creates computational work:
- Each animation step requires GPU/CPU computation for filter and transform operations
- Multiple parallel animation layers multiply the computational cost
- Steps-based animations ensure the exact iteration count is processed
- Cannot be bypassed without performing the actual rendering work
- Bot Resistance: Most automated bots run on CPUs without GPUs. Unlike CPU-based PoW challenges, CSS filter operations require GPU acceleration for reasonable performance, forcing bots to either use expensive GPU resources or suffer slow CPU rendering. Meanwhile, virtually all real human users have GPUs (integrated or dedicated), allowing them to complete the challenge quickly
- Economic Cost: Bots must expend real computational resources (GPU/CPU time)
- Stateless: Server only validates signatures, no session storage required
- Replay Protection: Nonce and timestamp prevent replay attacks
- Hardware Variance: GPUs complete work much faster than CPUs (seconds vs minutes)
- Distributed Attacks: Doesn't prevent distributed botnets with many IPs
- Farm Attacks: Specialized GPU farms can bypass iteration requirements
- No True Time-Lock: Actual completion time varies dramatically by hardware
- Adjust
WORK_DIFFICULTY_ITERATIONSbased on your threat model (1000-3000 for low security, 20000+ for high) - Combine with IP rate limiting
- Use HTTPS to prevent MITM tampering with challenge
- Rotate
SECRET_KEYregularly
Returns the captcha HTML form with embedded challenge.
Validates form submission with proof of work.
Parameters:
username: User's usernameemail: User's emailxcaptcha_challenge: Challenge stringxcaptcha_timestamp: Unix timestampxcaptcha_nonce: Random noncexcaptcha_signature: HMAC signaturexcaptcha_verified: Checkbox indicating completion
Returns JSON challenge for programmatic access.
Response:
{
"challenge": "a1b2c3d4...",
"timestamp": "1709832000",
"nonce": "e5f6g7h8...",
"signature": "i9j0k1l2...",
"work_iterations": 10000,
"work_iterations_2": 6700,
"estimated_seconds": 100.0
}Note: estimated_seconds is a rough estimate assuming CPU-only rendering. Actual time depends heavily on GPU acceleration (can be 10-50x faster).
API endpoint for challenge verification.
Request:
{
"challenge": "a1b2c3d4...",
"timestamp": "1709832000",
"nonce": "e5f6g7h8...",
"signature": "i9j0k1l2..."
}Response:
{
"valid": true,
"message": "Work verified successfully"
}| Browser | Version | Status |
|---|---|---|
| Chrome | 90+ | ✅ Full Support |
| Firefox | 88+ | ✅ Full Support |
| Safari | 14+ | ✅ Full Support |
| Edge | 90+ | ✅ Full Support |
| Opera | 76+ | ✅ Full Support |
Note: Requires CSS animation and filter support
Actual completion times vary dramatically by hardware:
| Hardware Type | Typical Time for 10,000 iterations |
|---|---|
| High-end Dedicated GPU (RTX 3070) | 1-3 seconds |
| Modern Integrated Graphics (Iris Xe) | 3-8 seconds |
| Older Integrated Graphics | 15-45 seconds |
| CPU-only rendering | 60-120 seconds |
Note: CSS filter operations are GPU-accelerated, making completion times highly dependent on graphics hardware.
Increase difficulty by modifying CSS custom properties and server config:
.xcaptcha-widget {
--xcaptcha-duration: 6s; /* Increase duration */
--xcaptcha-steps: 1200; /* More computation steps */
}Update server config:
WORK_DIFFICULTY_ITERATIONS = 20000 # Double the workModify the CSS to match your brand:
.xcaptcha-box {
border: 2px solid #your-brand-color;
background: #your-brand-bg;
}MIT License - Feel free to use in your projects!
Contributions welcome! Areas for improvement:
- Additional animation algorithms
- Better mobile optimization
- Accessibility enhancements
- Additional verification methods
- Inspired by the CSS-only game development community
- Leverages techniques from "The CSS3 Checkbox Hack"
- Proof of work concept from Hashcash and Bitcoin