Supported topologies: where each kind of evidence is actually available

Diátaxis quadrant: Reference. Audience: integrators and platform engineers deciding where to place humanymous, and evaluators checking which evidence is available before benchmarking.

This page is limitations-first. The single most important fact about deploying humanymous is that its detection layers are not all active in every topology — some depend on the process terminating raw TLS on its own accept loop, and one of the two shipped binaries does not capture them at all. If you benchmark the rich demo engine and then deploy the reverse proxy, or you place either behind a TLS-terminating CDN, you inherit a materially weaker detector and nothing in the request path will tell you. This page maps exactly what is active where, so you size expectations to your real topology, not the demo.

This repository is a reference implementation, not a production-hardened build. Where a capability is deferred to production, this page says so and links production vs reference.

The one fact to take away first

The complete Core pipeline splits into two groups by where the evidence comes from:

  • browser-side evidence — the complete Core bundle collects JavaScript and WebAssembly evidence. Gate’s current loader supplies a smaller report; injection alone does not make the complete browser plane active.
  • network and consistency evidence — Core can derive connection fingerprints and cross-checks when it directly terminates and parses the original client connection. Gate currently does not implement that extraction.

If an intermediary re-terminates the encrypted connection before Core, Core sees the intermediary’s connection, not the browser’s. Gate lacks the complete connection-fingerprint plane in both direct and re-terminated topologies.

The two shipped surfaces are not equivalent detectors

There are two binaries, and they do not have the same detection coverage. This is the gap most likely to surprise you.

Surface Binary Client plane (browser-side collection stages) Network plane (network and consistency-check TLS/H2) Notes
Core detection engine cmd/server (:8443) Yes Yes — captures the raw ClientHello + H2 frames on its own accept loop The rich demo/reference surface. What most people benchmark.
Gate reverse proxy cmd/gate (:8444) Reduced — current loader, not Core’s full report No — Gate does not currently extract the ClientHello The component deployed in front of an origin. Do not reuse Core accuracy claims.

The consequence, stated plainly: an integrator who evaluates the Core engine and then deploys the Gate loses the network plane. Gate currently has its reduced browser loader plus edge observations such as headers, request behavior, and client address intelligence. It does not receive Core’s full browser report or capture the browser’s encryption handshake and HTTP/2 frames. Gate logs that limitation at startup. If production requires connection fingerprints, add raw ClientHello and HTTP/2 capture to Gate’s accept loop (Core’s captureListener is the reference pattern), or deploy Core as the encrypted-connection terminator. See production vs reference.

Topology matrix: what fires where

Read your intended topology across the row. “Client” = browser-side collection stages, “Network” = network and consistency-check TLS/H2, “Headers/IP” = header-order + IP-intel heuristics + behavioral rate/correlation.

Topology Who terminates the browser’s TLS Client (browser-side collection stages) Network (network and consistency-check) Headers / IP / behavior Verdict quality
Core engine, direct-facing The Core itself Active Active Active Full — the design’s intended shape
Gate proxy, direct-facing The Gate itself Reduced Inactive (Gate does not capture ClientHello) Active Reduced — no connection-handshake or HTTP/2-frame evidence
Core/Gate behind a transport-pass-through load balancer (Proxy Protocol) The humanymous process Full on Core / reduced on Gate Active on Core / inactive on Gate Active (real client address recovered through Proxy Protocol version 2) As direct-facing; address-keyed state stays correct
Core/Gate behind a CDN or application-layer load balancer that re-terminates TLS The CDN / application-layer load balancer Active Inactive — silently Active, but IP is the CDN’s unless XFF is trust-configured Weakest — client plane + headers only
Behind a corporate encrypted-traffic inspection proxy (client side) The inspection proxy Full on Core / reduced on Gate Active on Core, but mismatched — the connection fingerprint belongs to the proxy, not the user’s browser Active Risk of false positives from browser and connection-fingerprint inconsistencies; see limitations

Two rows deserve emphasis:

  • Behind a content delivery network or application-layer load balancer, the network plane is inert and silent. This common production topology removes the evidence used to distinguish browser connections from libraries that imitate their encryption handshake. The reference build does not import connection fingerprints supplied by an intermediary. Treat such an import as a production integration, and do not claim network-plane coverage until it is implemented and tested.
  • Transport pass-through keeps Core’s network plane while still load-balancing. Terminate the encrypted connection at Core, put a transport-layer load balancer in front, and use Proxy Protocol version 2 if Core needs the original client address. Do not put a re-terminating intermediary ahead of it. See the -trusted-proxies flag in command-line, configuration, and per-route policy.
flowchart TB
  subgraph GOOD["Network plane ACTIVE"]
    direction LR
    B1["Browser"] -->|"raw encrypted connection"| Pass["Transport-pass-through load balancer<br/>(Proxy Protocol version 2 optional)"] -->|"raw encrypted connection"| C1["humanymous Core<br/>terminates connection · reads ClientHello"]
  end
  subgraph BAD["Network plane INERT (silent)"]
    direction LR
    B2["Browser"] -->|"raw encrypted connection"| CDN["Content delivery network / web application firewall / application load balancer<br/>re-terminates encryption"] -->|"new encrypted connection"| C2["humanymous<br/>sees the intermediary's ClientHello"]
  end

The hosting-network signal needs a dataset (it now fails open)

The machine signal l5.ip.datacenter_asn flags requests from known cloud or hosting address ranges. It depends on a real autonomous-system and cloud-address dataset, which the reference build does not ship. Without that dataset it deliberately fails open and flags no one. An earlier placeholder treated every public address as a hosting address, which challenged all real users outside loopback. Missing this signal is safer than challenging everyone, so it remains silent until an integrator supplies verified ranges through SetDatacenterCIDRs.

Single-node by default; what scales and what does not

humanymous defaults to single-node, in-process state. Only three kinds of shared state have a distribution seam today (an experimental, off-by-default -redis backend): bans, sticky verdicts, and the rate limiter. Everything else is per-process in memory:

  • Cross-session correlation (residential-proxy-rotation catch, cross-session correlation rule)
  • The recon sweep detector (decision-probing sweep protection)
  • The nonce caches (anti-replay)
  • The Core’s request-integrity token counter and proof of work solve-state

The consequence for a multi-node deployment behind a load balancer: correlation, sweep, and nonce anti-replay weaken as node count rises, and replicating the Core desyncs request-integrity token counters (spurious missing or replayed request-integrity token rule friction) and loses proof of work state (re-challenging users who already solved). Until those seams exist, the supported scale-out shape is: cap the Core to a single vertically-scaled node, or accept single-node correlation limits and pin verdict/token continuity with a shared token key (HMN_TOKEN_KEY) and the -redis ban/verdict backend. See CLI flags and production vs reference.

Clock dependence

Three mechanisms derive a value from wall-clock time buckets and therefore assume loosely-synchronized clocks (NTP) across any fleet: the request-integrity token time bucket, the origin-cloaking epoch, and the verdict-token epoch. Each tolerates roughly ±1 bucket of skew as a grace window. A node whose clock drifts more than a bucket past its peers will see spurious request-integrity token/token friction. Run NTP; do not deploy a fleet with unsynchronized clocks.

The attested preset adds an attestation floor on operator-marked high-value routes: a scoring-ALLOW there is priced to CHALLENGE → Pass unless the session presents possession or a step-up proof. That step-up proof depends on a topology prerequisite — it belongs alongside the port and co-location facts in install requirements, because it is a placement constraint, not a runtime tunable.

The mechanism: on a verified Pass solve the Core mints a session-bound receipt; the Gate redeems it at POST /__hmn/stepup and issues the hmn_su proof. The receipt is bound only to the hsid session id. So the Core-Pass front-end and the Gate must serve hsid in the same cookie jar, or the id the Gate reads will not match the id the receipt was minted for. Note this is not a same-origin requirement:

Placement of Core-Pass relative to the Gate Shared hsid? Result
Same host, different ports Yes — cookies are not port-scoped Works
Pass proxied through the Gate Yes — one origin Works
Split-domain / cross-subdomain Pass, no shared cookie Domain on hsid No — hsid diverges verifyStepUpReceipt returns a sid mismatch and 403s indefinitely; hmn_su is never minted; a real human loops on the route

The failure mode is bounded but permanent until fixed: a diverged cookie jar is never a DENY and never clears itself — the human keeps solving the Pass without ever getting the fast-path. Because a valid-signature/wrong-sid receipt is a cross-plane misconfiguration (not automated traffic), the Gate logs it with an actionable reason rather than a blanket block.

To deploy attested routes correctly:

  • Co-serve the Core-Pass front-end through the Gate, or set a shared cookie Domain on hsid so it is the same value on both planes.
  • Set a shared HMN_TOKEN_KEY across the Core and the Gate — the receipt is signed with it and verified with it; without a shared key the receipt cannot verify at all.

See Configure attested routes for the route-marking and end-to-end redemption walkthrough.

Checklist: pick your topology deliberately

  • If you want the complete seven-stage verdict, deploy the Core engine as the encrypted-connection terminator, direct-facing or behind a transport-pass-through load balancer, with no re-terminating intermediary in front.
  • If you must sit behind a content delivery network or application-layer load balancer, expect the network plane to be inert and size detection to the evidence that remains. Importing intermediary-supplied connection fingerprints requires a separate production integration.
  • If you deploy the Gate proxy, know that it captures no connection fingerprints today and receives only a reduced browser report; it is primarily the enforcement, injection, and audit surface.
  • If you scale out: keep the Core single-node, or accept the documented multi-node correlation/nonce/request-integrity token limits; enable the -redis ban/verdict backend and a shared HMN_TOKEN_KEY.
  • If you run attested routes: co-serve Core-Pass through the Gate (or share a cookie Domain on hsid) so hsid does not diverge, and set a shared HMN_TOKEN_KEY on both planes — otherwise the step-up receipt never verifies and humans loop on the route.
  • Run NTP on every node.