unmask

Shared feed

Community-sourced bot reports — on by default, a challenge rather than a block; sharing your own is opt-in.

unmask installs can opt in to share their BAN button decisions with the community feed. Pulling and enforcing the feed is on by default: installs challenge matching IP / JA4 / IP+JA4 pairs unless the operator sets the feed to browse-only or off. By default a match gets a proof-of-work step and then a CAPTCHA, so a person caught by a wrong report can still get through; operators who trust the feed can choose deny instead.

📤 Submit (opt-in per BAN)

In admin → settings → Community Bans, agree to the terms once. The BAN button on the hunt page then includes a Share checkbox and a 280-char comment field.

Submissions are tied to a pseudonymous token, not an account: no email, no name. You can stop sharing any time, and entries rotate out of the public feed a fixed period after their most recent report (see the privacy policy).

📥 Subscribe (on by default)

subscribe_mode defaults to fetch_apply: unmask pulls the feed every hour and enforces matches. Set it to fetch to pull for the browse list only, or off to stop. A match gets the Community Bans action, pow_then_captcha by default (captcha_only, pow_only and deny can be selected); search bots and bypass IPs are always exempt. Pulling starts with a one-time registration with the hub; the privacy policy lists what it stores.

Browse what you’re currently pulling at /admin/community-bans/.

How a report becomes a feed entry

  1. An admin presses BAN on the hunt page with Share checked.
  2. The IP / JA4 / reason / comment, and which kind of BAN it was, travel to the hub over TLS.
  3. The hub aggregates by (IP, JA4) and scores the reports with rule-based checks; it can also ask an AI model for a second opinion.
  4. When the reports meet the hub's rules (typically, enough independent installs reporting the same target), the hub publishes the entry with one of three match kinds — ip_ja4, ja4_only, or ip_only.
  5. Installs that enforce the feed (the default) fetch it on their next hourly pull and challenge matching requests (with the nginx module, from the next nginx reload).
Why a challenge, not a block? Because a community feed will inevitably get false positives — a shared IP, a hosting provider, your friend on a VPN. Blocking outright would punish real humans for someone else’s report. A challenge lets humans through, while keeping the cost high enough that crawlers move on. The default puts a proof-of-work step in front of the CAPTCHA, which also shows whether the matched traffic can run JavaScript at all; operators who trust the feed can pick deny.
No private feeds. There is a single public hub at unmask.sh, run by the unmask project as a separate service; the hub software is not part of the unmask package. If you would rather not use the shared feed, set subscribe_mode to off.