<!-- Markdown version of the Capcat doc "Protection Stack" (rendered page: https://capcat.ai/guide/protection.html). Docs index: https://capcat.ai/llms.txt, full single-file version: https://capcat.ai/llms-full.txt -->

# Protection Stack

Base Capcat uses no image puzzles or third-party tracking cookies. It stacks independent layers that each make automated abuse more expensive. PoW, environment attestation, and off-the-shelf automation blocking are on by default. Behavior scoring, adaptive treatment, and third-party providers each require both a site opt-in and an operator runtime gate. Shipped code or a visible console control does not mean that layer is active on production traffic.

## Proof of work — the base layer

Every verification requires the browser to solve a SHA-256 proof-of-work challenge, powered by the open-source [Cap](https://github.com/tiagozip/cap) engine. It runs silently in the background: a real user notices at most a sub-second delay, while bulk abuse has to pay CPU time for every single attempt.

## Environment attestation

Alongside each challenge, Capcat ships a dynamically generated attestation program that must run to completion where the solving happens. It confirms the solve took place inside a real browser — a script that calls the API directly (curl, Python, a Node bot) cannot redeem a token even if it computes the proof of work correctly. The program is generated fresh and randomized per challenge, so there is no fixed checklist to hardcode around. On by default for every site.

## Automated browser blocking

Off-the-shelf automation tooling — Selenium, Playwright, Puppeteer, and headless browsers in general — is detected and rejected on both the client and the server. Capcat maintains and continuously hardens this detection on top of the upstream engine, with the highest-confidence signals checked on every challenge. On by default; you can switch it off per site if your audience includes real users running automation-style browser extensions.

This layer targets stock-tool fingerprints. It does not promise to stop patched stealth browsers, real-browser solving services, or human-assisted attacks. Residual automation that passes static attestation needs the behavior, velocity, provider-score, and backend-policy layers below.

## Bounded behavior and Account Defense — staged

When both the site and operator runtime gates are enabled, the widget follows a signed policy to collect at most 15 seconds and 128 samples of mouse/touch/keyboard, activation, focus, and visibility aggregates. It sends bounded histograms and statistics, never raw coordinates or event sequences. Re-copy the console-generated embed so it includes `data-cap-behavior-signals` when you want the signed policy prefetched early enough to cover the approach to the checkbox. Existing embeds discover it during the first-interaction prefetch window, so a very fast first click may have activation coverage only.

The server can combine those aggregates with network provenance, hosting ASN, and short-window velocity into `risk_score`, bind it to the one-time token, and return it only from authenticated `/siteverify`. Your registration backend then decides whether to allow, step up, or reject. These fields exist only when the console runtime card explicitly shows **Collection**, **Token metadata**, and **Score response** as enabled; never treat a missing field as low risk. The current development ML candidate is isolated shadow output and does not block production traffic.

## Adaptive difficulty

The adaptive pipeline can temporarily raise proof-of-work difficulty when a site's traffic pattern looks abusive, then lower it as traffic normalizes. It is not fleet-wide by default: ingestion, alerting, warm-up, canary, and rollback gates must pass before an operator expands it. Do not infer that a site is automatically hardened merely because this capability appears in the console or documentation.

## Time-lock puzzles (RSW) — opt-in

For high-value endpoints — signup, checkout, promo redemption — you can enable an RSW time-lock puzzle: a computation that is inherently sequential and cannot be accelerated with more cores or GPUs. Every verification then takes a fixed wall-clock time regardless of hardware, capping any bot fleet at a constant per-client rate. Strength is tunable per site; the default adds roughly 0.5–2 seconds.

## Cloudflare Turnstile (Invisible) — optional

You can add a customer-owned Turnstile widget as a defense-in-depth check. This is an advanced paid-plan feature (administrators and internal accounts receive the same access): Free accounts do not see its Console settings, and a downgrade disables it at runtime while retaining saved credentials for a later upgrade. It is off by default. Create the widget with **Widget mode: Invisible** in Cloudflare — `invisible` is a widget mode, not a client-side `size` option. When enabled, activating the Capcat checkbox starts Turnstile and the Capcat challenge together; the widget sends both results in one redeem request.

It runs only after BYOK credentials are saved, the base snapshot has converged, and runtime mode is actually `observe` or `strict`. A defaults-off dark deploy changes no requests.

- **Observe** runs and measures Turnstile but never lets its rejection or an outage block an otherwise valid Capcat solve. Use this first to measure compatibility and false positives.
- **Strict** requires both checks. A missing or rejected token returns `403`; a server-side Siteverify network, rate-limit, or internal failure returns a retryable `503`.

Capcat validates its signed challenge and consumes its nonce before calling Cloudflare, so arbitrary invalid requests cannot directly spend provider validations. The server also checks Turnstile's `hostname`, signed action, and challenge-bound `cData`; the provider secret is stored only as site-bound AES-GCM ciphertext and is never returned to the browser.

This mode loads third-party code from `https://challenges.cloudflare.com` and sends Cloudflare the network and browser signals needed for verification. Cloudflare requires sites using Invisible mode to reference the [Turnstile Privacy Addendum](https://www.cloudflare.com/turnstile-privacy-policy/) in their privacy policy. If you use CSP, allow that origin in at least `script-src` and `frame-src`. Strict mode requires a normal browser `Origin`; it is not suitable for native clients using the “allow no Origin” exception.

## Google reCAPTCHA v3 — optional

You can also bring a classic reCAPTCHA v3 site key and secret. It uses the same paid-feature entitlement as Turnstile, remains independently optional, and can run at the same time. Capcat executes v3 only when the user activates the checkbox, then verifies Google's `success`, `hostname`, `action`, and numeric `score` on the server before issuing the Capcat token.

This is also defaults-off. Google is loaded only after credentials, privacy disclosure, base-snapshot convergence, and the site's enabled state are all in place. Deploying the code or setting the encryption master key alone produces no score and blocks nothing.

Set a minimum passing score from `0` to `1` in the console:

- `0.3` rejects scores below `0.3`, so the Capcat checkbox remains invalid;
- `0` accepts every **valid** provider score. It does not skip Google validation. The authenticated Capcat `/siteverify` response includes the score, allowing your backend to apply its own policy.

For example, a successful verification from a v3-enabled site can return `{ "success": true, "score": 0.7 }`. The score is bound to the opaque, single-use Capcat token and is not exposed in the browser's solve event. This avoids trusting a client-provided score while preserving the standard reCAPTCHA-style server response.

Google documents that v3 tokens expire after two minutes, must be verified once, and should be executed at the protected action rather than page load. Capcat follows that lifecycle and checks the expected action. See Google's [reCAPTCHA v3 guide](https://developers.google.com/recaptcha/docs/v3) and [server-side verification contract](https://developers.google.com/recaptcha/docs/verify).

Start with score observation on real traffic before choosing a blocking threshold. Google notes that
v3 scores depend on real traffic and recommends separate keys for test environments; automated test
scores are not a substitute for production calibration. See the [reCAPTCHA FAQ](https://developers.google.com/recaptcha/docs/faq).

Classic v3 can return a static `0.9` together with an `Over free quota.` error after its monthly allowance is exhausted. Capcat treats any provider-reported error as unavailable (`503`) instead of accepting that fallback score. Monitor your Google quota when using BYOK.

Enabling v3 loads third-party code from `www.google.com` and `www.gstatic.com`, and reCAPTCHA sets a necessary cookie for risk analysis. Add the appropriate privacy disclosure and allow Google's documented `script-src`, `frame-src`, and `connect-src` origins in CSP. Capcat leaves the reCAPTCHA badge visible; do not hide it unless you add Google's required Privacy Policy and Terms of Service text. The BYOK secret is stored only as site-bound AES-GCM ciphertext and never sent to the browser. Classic v3 keys are supported; reCAPTCHA Enterprise uses a different assessment API and is not accepted by this integration. Because Capcat checks the provider hostname against the browser `Origin`, this layer is not suitable for native or other no-Origin clients.

## Service-layer controls

- **Domain binding** — a site key only works from the origins you allow; anything else is rejected before it can spend your quota.
- **Single-use tokens** — a verification token redeems exactly once; replaying it fails.
- **Rate limits and quotas** — per-key rate limiting and monthly quotas keep runaway or hostile usage from becoming your problem.

## Honest limits

No CAPTCHA — commercial ones included — stops a determined attacker armed with patched stealth browsers and real hardware. The point of stacking independent layers is economics: CPU cost per attempt, constant-rate time locks, environment checks that break off-the-shelf tooling, and difficulty that rises exactly when abuse starts. An optional independent provider can add another signal, but also adds its availability and privacy tradeoffs. We document that plainly instead of promising magic.

The [console](https://console.capcat.ai) **Protection** card shows configuration intent separately from runtime state. During a rollout freeze, writes are explicitly rejected and a read-only control must not be interpreted as enabled. After the freeze is lifted, base-snapshot publication and multi-POP verification still determine when a change is live; there is no unconditional one-minute promise.
