Skip to content

Releases: TecharoHQ/anubis

v1.24.0-pre1: Y'shtola Rhul Prerelease 1

02 Dec 13:09
@Xe Xe

Choose a tag to compare

Anubis is back and better than ever! Lots of minor fixes with some big ones interspersed.

  • Fix panic when validating challenges after privacy-mode browsers strip headers and the follow-up request matches an ALLOW threshold.
  • Expose WEIGHT rule matches as Prometheus metrics.
  • Allow more OCI registry clients based on feedback.
  • Expose services directory in the embedded (data) filesystem.
  • Add Ukrainian locale (#1044).
  • Allow Renovate as an OCI registry client.
  • Properly handle 4in6 addresses so that IP matching works with those addresses.
  • Add support to simple Valkey/Redis cluster mode
  • Open Graph passthrough now reuses the configured target Host/SNI/TLS settings, so metadata fetches succeed when the upstream certificate differs from the public domain. (1283)
  • Stabilize the CVE-2025-24369 regression test by always submitting an invalid proof instead of relying on random POW failures.

Deprecate report_as in challenge configuration

Previously Anubis let you lie to users about the difficulty of a challenge to interfere with operators of malicious scrapers as a psychological attack:

bots:
  # Punish any bot with "bot" in the user-agent string
  # This is known to have a high false-positive rate, use at your own risk
  - name: generic-bot-catchall
    user_agent_regex: (?i:bot|crawler)
    action: CHALLENGE
    challenge:
      difficulty: 16 # impossible
      report_as: 4 # lie to the operator
      algorithm: slow # intentionally waste CPU cycles and time

This has turned out to be a bad idea because it has caused massive user experience problems and has been removed. If you are using this setting, you will get a warning in your logs like this:

{
  "time": "2025-11-25T23:10:31.092201549-05:00",
  "level": "WARN",
  "source": {
    "function": "github.com/TecharoHQ/anubis/lib/policy.ParseConfig",
    "file": "/home/xe/code/TecharoHQ/anubis/lib/policy/policy.go",
    "line": 201
  },
  "msg": "use of deprecated report_as setting detected, please remove this from your policy file when possible",
  "at": "config-validate",
  "name": "mild-suspicion"
}

To remove this warning, remove this setting from your policy file.

Logging customization

Anubis now supports the ability to log to multiple backends ("sinks"). This allows you to have Anubis log to a file instead of just logging to standard out. You can also customize the logging level in the policy file:

logging:
  level: "warn" # much less verbose logging
  sink: file # log to a file
  parameters:
    file: "./var/anubis.log"
    maxBackups: 3 # keep at least 3 old copies
    maxBytes: 67108864 # each file can have up to 64 Mi of logs
    maxAge: 7 # rotate files out every n days
    oldFileTimeFormat: 2006-01-02T15-04-05 # RFC 3339-ish
    compress: true # gzip-compress old log files
    useLocalTime: false # timezone for rotated files is UTC

Additionally, information about how Anubis uses each logging level has been added to the documentation.

DNS Features

  • CEL expressions for:
    • FCrDNS checks
    • Forward DNS queries
    • Reverse DNS queries
    • arpaReverseIP to transform IPv4/6 addresses into ARPA reverse IP notation.
    • regexSafe to escape regex special characters (useful for including remoteAddress or headers in regular expressions).
  • DNS cache and other optimizations to minimize unnecessary DNS queries.

The DNS cache TTL can be changed in the bots config like this:

dns_ttl:
  forward: 600
  reverse: 600

The default value for both forward and reverse queries is 300 seconds.

The verifyFCrDNS CEL function has two overloads:

  • (addr)
    Simply verifies that the remote side has PTR records pointing to the target address.
  • (addr, ptrPattern)
    Verifies that the remote side refers to a specific domain and that this domain points to the target IP.

What's Changed

  • feat: Add thai language. by @karorogunso in #900
  • Update is.json by @sveinki in #1241
  • fix(data/docker-client): allow some more OCI clients through by @Xe in #1258
  • fix(data): add services folder to embedded filesystem by @Xe in #1259
  • feat(localization): Add Ukrainian language translation by @nykula in #1044
  • build(deps): bump the github-actions group with 3 updates by @dependabot[bot] in #1262
  • Add Renovate to Docker clients by @DrJosh9000 in #1267
  • fix(docs): use node:lts by @Xe in #1274
  • fix(run): mark openrc service script as executable by @kouhaidev in #1272
  • test: ipv4 in v6 address checking by @SlyEcho in #1271
  • (feat) Add cluster support to redis/vaultkey store by @egimbernat in #1276
  • feat(lib): expose WEIGH matches as prometheus metrics by @Xe in #1277
  • Fix challenge validation panic when follow-up hits ALLOW by @JasonLovesDoggo in #1278
  • feat(internal/headers): extend debug logging of X-Forwarded-For middlewares by @DerRockWolf in #1269
  • test: Valkey test improvements for testcontainers by @SlyEcho in #1280
  • docs: use nginx http2 directive instead of deprecated http2 listen parameter by @kouhaidev in #1251
  • perf: field-align struct definitions to cut padding by @JasonLovesDoggo in #1284
  • fix(tests): make CVE-2025-24369 regression deterministic by @JasonLovesDoggo in #1285
  • build(deps): bump go deps by @JasonLovesDoggo in #1287
  • build(deps): bump github.com/testcontainers/testcontainers-go from 0.39.0 to 0.40.0 in the gomod group across 1 directory by @dependabot[bot] in #1288
  • test(deps): update dependencies to latest versions by @JasonLovesDoggo in #1289
  • build(deps-dev): bump esbuild from 0.25.12 to 0.27.0 in the npm group by @dependabot[bot] in #1260
  • fix(ogtags): respect target host/SNI/insecure flags in OG passthrough by @JasonLovesDoggo in #1283
  • docs: clarify usage of PUBLIC_URL and REDIRECT_DOMAINS in installatio… by @JasonLovesDoggo in #1286
  • feat(store/valkey): Add Redis(R) Sentinel support by @Xe in #1294
  • Pass the remote IP to the proxied application by @eXpl0it3r in #1298
  • ci: add go mod tidy check workflow by @Xe in #1300
  • feat: writing logs to the filesystem with rotation support by @Xe in #1299
  • chore: add dependabot cooldown by @Xe in #1302
  • add Polish language translation by @bplajzer in #1309
  • fix(config): deprecate the report_as field for challenges by @Xe in #1311
  • Implement FCrDNS and other DNS features by @btomaev in #1308
  • Show how to use subrequest auth with Caddy by @tbodt in #1312
  • build(deps): bump actions-hub/kubectl from 1.34.1 to 1.34.2 in the github-actions group by @dependabot[bot] in #1303
  • fix: pin Node.js and Go versions in CI configuration files by @JasonLovesDoggo in #1318
  • build(deps): bump the github-actions group with 3 updates by @dependabot[bot] in #1317
  • build(deps): bump the gomod group with 5 updates by @dependabot[bot] in #1316

New Contributors

Full Changelog: v1.23.1...v1.24.0-pre1

v1.23.1: Lyse Hext - Echo 1

08 Nov 00:43
@Xe Xe

Choose a tag to compare

  • Fix SERVE_ROBOTS_TXT setting after the double slash fix broke it.

Potentially breaking changes

Remove default Tencent Cloud block rule

v1.23.0 added a default rule to block Tencent Cloud. After an email from their abuse team where they promised to take action to clean up their reputation, I have removed the default block rule. If this network causes you problems, please contact [email protected] and supply the following information:

  • Time of abusive requests.
  • IP address, User-Agent header, or other unique identifiers that can help the abuse team educate the customer about their misbehaving infrastructure.
  • Does the abusive IP address request robots.txt? If not, be sure to include that information.
  • A brief description of the impact to your system such as high system load, pages not rendering, or database system crashes. This helps the provider establish the fact that their customer is causing you measurable harm.
  • Context as to what your service is, what it does, and why they should care.

Mention that you are using Anubis or BotStopper to protect your services. If they do not respond to you, please contact me as soon as possible.

Docker / OCI registry clients

Anubis v1.23.0 accidentally blocked Docker / OCI registry clients. In order to explicitly allow them, add an import for (data)/clients/docker-client.yaml:

bots:
  - import: (data)/meta/default-config.yaml
  - import: (data)/clients/docker-client.yaml

This is technically a regression as these clients used to work in Anubis v1.22.0, however it is allowable to make this opt-in as most websites do not expect to be serving Docker / OCI registry client traffic.

What's Changed

  • fix: SERVE_ROBOTS_TXT works again by @Xe in #1229
  • chore(default-config): remove Tencent Cloud block rule by @Xe in #1227
  • feat(blog): a short post on how to file abuse reports by @Xe in #1230
  • build(deps-dev): bump the npm group across 1 directory with 3 updates by @dependabot[bot] in #1238
  • build(deps): bump github/codeql-action from 4.31.0 to 4.31.2 in the github-actions group by @dependabot[bot] in #1239
  • build(deps): bump the gomod group across 1 directory with 18 updates by @dependabot[bot] in #1237
  • fix(data): add ruleset to explicitly allow Docker / OCI clients by @Xe in #1253
  • ci: add asset build verification workflow by @Xe in #1254

Full Changelog: v1.23.0...v1.23.1

v1.23.0: Lyse Hext

30 Oct 00:43
@Xe Xe

Choose a tag to compare

Sorry this took so long, work has been wiping me out. If you know of any companies that are hiring for someone of my skillset, please let me know.

  • Add default tencent cloud DENY rule.
  • Added (data)/meta/default-config.yaml for importing the entire default configuration at once.
  • Add -custom-real-ip-header flag to get the original request IP from a different header than x-real-ip.
  • Add contentLength variable to bot expressions.
  • Add COOKIE_SAME_SITE_MODE to force anubis cookies SameSite value, and downgrade automatically from None to Lax if cookie is insecure.
  • Fix lock convoy problem in decaymap (#1103).
  • Fix lock convoy problem in bbolt by implementing the actor pattern (#1103).
  • Remove bbolt actorify implementation due to causing production issues.
  • Document missing environment variables in installation guide: SLOG_LEVEL, COOKIE_PREFIX, FORCED_LANGUAGE, and TARGET_DISABLE_KEEPALIVE (#1086).
  • Add validation warning when persistent storage is used without setting signing keys.
  • Fixed robots2policy to properly group consecutive user agents into any: instead of only processing the last one (#925).
  • Make the fast algorithm prefer purejs when running in an insecure context.
  • Add the s3api storage backend to allow Anubis to use S3 API compatible object storage as its storage backend.
  • Fix a "stutter" in the cookie name prefix so the auth cookie is named techaro.lol-anubis-auth instead of techaro.lol-anubis-auth-auth.
  • Make cmd/containerbuild support commas for separating elements of the --docker-tags argument as well as newlines.
  • Add the DIFFICULTY_IN_JWT option, which allows one to add the difficulty field in the JWT claims which indicates the difficulty of the token (#1063).
  • Ported the client-side JS to TypeScript to avoid egregious errors in the future.
  • Fixes concurrency problems with very old browsers (#1082).
  • Randomly use the Refresh header instead of the meta refresh tag in the metarefresh challenge.
  • Update OpenRC service to truncate the runtime directory before starting Anubis.
  • Make the git client profile more strictly match how the git client behaves.
  • Make the default configuration reward users using normal browsers.
  • Allow multiple consecutive slashes in a row in application paths (#754).
  • Add option to set targetSNI to special keyword 'auto' to indicate that it should be automatically set to the request Host name (424).
  • The Preact challenge has been removed from the default configuration. It will be deprecated in the future.
  • An open redirect when in subrequest mode has been fixed.

Potentially breaking changes

Multiple checks at once has and-like semantics instead of or-like semantics

Anubis lets you stack multiple checks at once with blocks like this:

name: allow-prometheus
action: ALLOW
user_agent_regex: ^prometheus-probe$
remote_addresses:
  - 192.168.2.0/24

Previously, this only returned ALLOW if any one of the conditions matched. This behaviour has changed to only return ALLOW if all of the conditions match. I expect this to have some issues with user configs, however this fix is grave enough that it's worth the risk of breaking configs. If this bites you, please let me know so we can make an escape hatch.

Better error messages

In order to make it easier for legitimate clients to debug issues with their browser configuration and Anubis, Anubis will emit internal error detail in base 64 so that administrators can chase down issues. Future versions of this may also include a variant that encrypts the error detail messages.

Bug Fixes

Sometimes the enhanced temporal assurance in #1038 and #1068 could backfire because Chromium and its ilk randomize the amount of time they wait in order to avoid a timing side channel attack. This has been fixed by both increasing the amount of time a client has to wait for the metarefresh and preact challenges as well as making the server side logic more permissive.

What's Changed

  • docs(installation): add SLOG_LEVEL environment variable to configuration by @JasonLovesDoggo in #1086
  • docs: document some missing env vars by @JasonLovesDoggo in #1087
  • build(deps): bump the github-actions group across 1 directory with 8 updates by @dependabot[bot] in #1071
  • fix(robots2policy): handle multiple user agents under one block by @JasonLovesDoggo in #925
  • feat(lib/store): add s3api storage backend by @Xe in #1089
  • Xe/demote temporal assurance by @Xe in #1090
  • feat: Warn on missing signing keys when persisting challenges by @JasonLovesDoggo in #1088
  • docs: add reminder for verified signatures in PR template by @JasonLovesDoggo in #1092
  • build(deps): bump the github-actions group with 4 updates by @dependabot[bot] in #1093
  • security: npm audit fix for GHSA-hfm8-9jrf-7g9w et. al by @Xe in #1098
  • fix(cmd/containerbuild): support commas in --docker-tags by @Xe in #1099
  • feat(lib): Add option for adding difficulty field to JWT claims by @Earl0fPudding in #1063
  • chore: port client-side JS to TypeScript by @Xe in #1100
  • fix(decaymap): fix lock convoy by @Xe in #1106
  • feat(store/bbolt): implement actor pattern by @Xe in #1107
  • feat: allow to set cookie sameSite mode and fallback to Lax mode if cookie is not secure by @vaab in #1105
  • docs: add link to preact in challenge list by @agoujot in #1111
  • ci: add aarch64 for ssh CI by @Xe in #1112
  • ci(ssh): don't print uname -av output by @Xe in #1114
  • feat(expressions): add contentLength to bot expressions by @Xe in #1120
  • fix(run/openrc): truncate runtime directory before starting Anubis by @CyberTailor in #1122
  • build(deps): bump the npm group with 2 updates by @dependabot[bot] in #1117
  • build(deps): bump the github-actions group with 3 updates by @dependabot[bot] in #1118
  • Update nl.json removing literal translated cookie 'koekje' with 'cookie' by @jieter in #1126
  • convert issue templates into issue forms by @NetSysFire in #1115
  • build(deps): bump github.com/docker/docker from 28.3.2+incompatible to 28.3.3+incompatible in /test by @dependabot[bot] in #1130
  • feat(metarefresh): randomly use the Refresh header by @Xe in #1133
  • Add Door43 link to known instances documentation by @richmahn in #1136
  • fix: mend auth cookie name stutter by @Xe in #1139
  • Update Nynorsk translation by @turtlegarden in #1143
  • feat: support reading real client IP from a custom header by @avioletheart in #1138
  • enable auto setting of SNI based on host header by @jmcclelland in #1129
  • fix(lib): enable multiple consecutive slash support by @Xe in #1155
  • build(deps-dev): bump esbuild from 0.25.9 to 0.25.10 in the npm group by @dependabot[bot] in #1147
  • build(deps): bump github.com/ulikunitz/xz from 0.5.12 to 0.5.14 by @dependabot[bot] in #1132
  • build(deps): bump github.com/docker/docker from 28.3.2+incompatible to 28.3.3+incompatible by @dependabot[bot] in #1131
  • fix(lib): serve CSS properly by @Xe in #1158
  • fix(default-config): make the default config far less paranoid by @Xe in #1179
  • fix(default-config): remove preact challenge by @Xe in #1184
  • feat: default config macro by @Xe in #1186
  • fix(lib): de-flake package lib tests by @Xe in #1187
  • Updated REDIRECT_DOMAINS documentation by @zc-devs in #1171
  • fix(default-config): sometimes browsers don't send Upgrade-Insecure-Requests by @Xe in #1189
  • fix(algorithms/fast): fix fast challenge on insecure contexts by @Xe in #1198
  • Xe/show error state by @Xe in #1203
  • locale: Update Nynorsk translation by @turtlegarden in #1204
  • docs: point get s...
Read more

v1.23.0-pre2: Lyse Hext

26 Oct 23:27
@Xe Xe

Choose a tag to compare

Pre-release

What's Changed

  • docs: point get started button to the per-environment setup docs by @Xe in #1213
  • fix(store/bbolt): remove actorify by @Xe in #1215
  • feat(default-config): block tencent cloud by default by @Xe in #1216
  • link to docs site from readme by @pushcx in #1214
  • fix!(policy/checker): make List and-like by @Xe in #1217
  • chore: remove copilot instructions by @Xe in #1218

New Contributors

Full Changelog: v1.23.0-pre1...v1.23.0-pre2

v1.23.0-pre1: Lyse Hext

22 Oct 14:43
@Xe Xe
2fc3765

Choose a tag to compare

Pre-release
  • Added (data)/meta/default-config.yaml for importing the entire default configuration at once.
  • Add -custom-real-ip-header flag to get the original request IP from a different header than x-real-ip.
  • Add contentLength variable to bot expressions.
  • Add COOKIE_SAME_SITE_MODE to force anubis cookies SameSite value, and downgrade automatically from None to Lax if cookie is insecure.
  • Fix lock convoy problem in decaymap (#1103).
  • Fix lock convoy problem in bbolt by implementing the actor pattern (#1103).
  • Document missing environment variables in installation guide: SLOG_LEVEL, COOKIE_PREFIX, FORCED_LANGUAGE, and TARGET_DISABLE_KEEPALIVE (#1086).
  • Add validation warning when persistent storage is used without setting signing keys.
  • Fixed robots2policy to properly group consecutive user agents into any: instead of only processing the last one (#925).
  • Make the fast algorithm prefer purejs when running in an insecure context.
  • Add the s3api storage backend to allow Anubis to use S3 API compatible object storage as its storage backend.
  • Fix a "stutter" in the cookie name prefix so the auth cookie is named techaro.lol-anubis-auth instead of techaro.lol-anubis-auth-auth.
  • Make cmd/containerbuild support commas for separating elements of the --docker-tags argument as well as newlines.
  • Add the DIFFICULTY_IN_JWT option, which allows one to add the difficulty field in the JWT claims which indicates the difficulty of the token (#1063).
  • Ported the client-side JS to TypeScript to avoid egregious errors in the future.
  • Fixes concurrency problems with very old browsers (#1082).
  • Randomly use the Refresh header instead of the meta refresh tag in the metarefresh challenge.
  • Update OpenRC service to truncate the runtime directory before starting Anubis.
  • Make the git client profile more strictly match how the git client behaves.
  • Make the default configuration reward users using normal browsers.
  • Allow multiple consecutive slashes in a row in application paths (#754).
  • Add option to set targetSNI to special keyword 'auto' to indicate that it should be automatically set to the request Host name (424).
  • The Preact challenge has been removed from the default configuration. It will be deprecated in the future.

Better error messages

In order to make it easier for legitimate clients to debug issues with their browser configuration and Anubis, Anubis will emit internal error detail in base 64 so that administrators can chase down issues. Future versions of this may also include a variant that encrypts the error detail messages.

Bug Fixes

Sometimes the enhanced temporal assurance in #1038 and #1068 could backfire because Chromium and its ilk randomize the amount of time they wait in order to avoid a timing side channel attack. This has been fixed by both increasing the amount of time a client has to wait for the metarefresh and preact challenges as well as making the server side logic more permissive.

What's Changed

  • docs(installation): add SLOG_LEVEL environment variable to configuration by @JasonLovesDoggo in #1086
  • docs: document some missing env vars by @JasonLovesDoggo in #1087
  • build(deps): bump the github-actions group across 1 directory with 8 updates by @dependabot[bot] in #1071
  • fix(robots2policy): handle multiple user agents under one block by @JasonLovesDoggo in #925
  • feat(lib/store): add s3api storage backend by @Xe in #1089
  • Xe/demote temporal assurance by @Xe in #1090
  • feat: Warn on missing signing keys when persisting challenges by @JasonLovesDoggo in #1088
  • docs: add reminder for verified signatures in PR template by @JasonLovesDoggo in #1092
  • build(deps): bump the github-actions group with 4 updates by @dependabot[bot] in #1093
  • security: npm audit fix for GHSA-hfm8-9jrf-7g9w et. al by @Xe in #1098
  • fix(cmd/containerbuild): support commas in --docker-tags by @Xe in #1099
  • feat(lib): Add option for adding difficulty field to JWT claims by @Earl0fPudding in #1063
  • chore: port client-side JS to TypeScript by @Xe in #1100
  • fix(decaymap): fix lock convoy by @Xe in #1106
  • feat(store/bbolt): implement actor pattern by @Xe in #1107
  • feat: allow to set cookie sameSite mode and fallback to Lax mode if cookie is not secure by @vaab in #1105
  • docs: add link to preact in challenge list by @agoujot in #1111
  • ci: add aarch64 for ssh CI by @Xe in #1112
  • ci(ssh): don't print uname -av output by @Xe in #1114
  • feat(expressions): add contentLength to bot expressions by @Xe in #1120
  • fix(run/openrc): truncate runtime directory before starting Anubis by @CyberTailor in #1122
  • build(deps): bump the npm group with 2 updates by @dependabot[bot] in #1117
  • build(deps): bump the github-actions group with 3 updates by @dependabot[bot] in #1118
  • Update nl.json removing literal translated cookie 'koekje' with 'cookie' by @jieter in #1126
  • convert issue templates into issue forms by @NetSysFire in #1115
  • build(deps): bump github.com/docker/docker from 28.3.2+incompatible to 28.3.3+incompatible in /test by @dependabot[bot] in #1130
  • feat(metarefresh): randomly use the Refresh header by @Xe in #1133
  • Add Door43 link to known instances documentation by @richmahn in #1136
  • fix: mend auth cookie name stutter by @Xe in #1139
  • Update Nynorsk translation by @turtlegarden in #1143
  • feat: support reading real client IP from a custom header by @avioletheart in #1138
  • enable auto setting of SNI based on host header by @jmcclelland in #1129
  • fix(lib): enable multiple consecutive slash support by @Xe in #1155
  • build(deps-dev): bump esbuild from 0.25.9 to 0.25.10 in the npm group by @dependabot[bot] in #1147
  • build(deps): bump github.com/ulikunitz/xz from 0.5.12 to 0.5.14 by @dependabot[bot] in #1132
  • build(deps): bump github.com/docker/docker from 28.3.2+incompatible to 28.3.3+incompatible by @dependabot[bot] in #1131
  • fix(lib): serve CSS properly by @Xe in #1158
  • fix(default-config): make the default config far less paranoid by @Xe in #1179
  • fix(default-config): remove preact challenge by @Xe in #1184
  • feat: default config macro by @Xe in #1186
  • fix(lib): de-flake package lib tests by @Xe in #1187
  • Updated REDIRECT_DOMAINS documentation by @zc-devs in #1171
  • fix(default-config): sometimes browsers don't send Upgrade-Insecure-Requests by @Xe in #1189
  • fix(algorithms/fast): fix fast challenge on insecure contexts by @Xe in #1198
  • Xe/show error state by @Xe in #1203
  • locale: Update Nynorsk translation by @turtlegarden in #1204

New Contributors

Full Changelog: v1.22.0...v1.23.0-pre1

v1.22.0: Yda Hext

06 Sep 15:57
@Xe Xe

Choose a tag to compare

Someone has to make an effort at reconciliation if these conflicts are ever going to end.

In this release, we finally fix the odd number of CPU cores bug, pave the way for lighter weight challenges, make Anubis more adaptable, and more.

Big ticket items

Proof of React challenge

A new "proof of React" has been added. It runs a simple app in React that has several chained hooks. It is much more lightweight than the proof of work check.

Smaller features

  • The segments function was added for splitting a path into its slash-separated segments.
  • Added possibility to disable HTTP keep-alive to support backends not properly handling it.
  • When issuing a challenge, Anubis stores information about that challenge into the store. That stored information is later used to validate challenge responses. This works around nondeterminism in bot rules. (#917)
  • One of the biggest sources of lag in Firefox has been eliminated: the use of WebCrypto. Now whenever Anubis detects the client is using Firefox (or Pale Moon), it will swap over to a pure-JS implementation of SHA-256 for speed.
  • Proof of work solving has had a complete overhaul and rethink based on feedback from browser engine developers, frontend experts, and overall performance profiling.
  • Optimize the performance of the pure-JS Anubis solver.
  • Web Workers are stored as dedicated JavaScript files in static/js/workers/*.mjs.
  • Pave the way for non-SHA256 solver methods and eventually one that uses WebAssembly (or WebAssembly code compiled to JS for those that disable WebAssembly).
  • Legacy JavaScript code has been eliminated.
  • When parsing Open Graph tags, add any URLs found in the responses to a temporary "allow cache" so that social preview images work.
  • The hard dependency on WebCrypto has been removed, allowing a proof of work challenge to work over plain (unencrypted) HTTP.
  • The Anubis version number is put in the footer of every page.
  • Add a default block rule for Huawei Cloud.
  • Add a default block rule for Alibaba Cloud.
  • Added support to use Traefik forwardAuth middleware.
  • Add X-Request-URI support so that Subrequest Authentication has path support.

Fixes

Odd numbers of CPU cores are properly supported

Some phones have an odd number of CPU cores. This caused interesting issues. This was fixed by using Math.trunc to convert the number of CPU cores back into an integer.

Smaller fixes

  • A standard library HTTP server log message about HTTP pipelining not working has been filtered out of Anubis' logs. There is no action that can be taken about it.
  • Added a missing link to the Caddy installation environment in the installation documentation.
  • Downstream consumers can change the default log/slog#Logger instance that Anubis uses by setting opts.Logger to your slog instance of choice (#864).
  • The Thoth client is now public in the repo instead of being an internal package.
  • Custom-AsyncHttpClient's default User-Agent has an increased weight by default (#852).
  • Add option for replacing the default explanation text with a custom one (#747)
  • The contact email in the LibreJS header has been changed.
  • Firefox for Android support has been fixed by embedding the challenge ID into the pass-challenge route. This also fixes some inconsistent issues with other mobile browsers.
  • The default favicon pattern in data/common/keep-internet-working.yaml has been updated to permit requests for png/gif/jpg/svg files as well as ico.
  • The --cookie-prefix flag has been fixed so that it is fully respected.
  • The default patterns in data/common/keep-internet-working.yaml have been updated to appropriately escape the '.' character in the regular expression patterns.
  • Add optional restrictions for JWT based on the value of a header (#697)
  • The word "hack" has been removed from the translation strings for Anubis due to incidents involving people misunderstanding that word and sending particularly horrible things to the project lead over email.
  • Bump AI-robots.txt to version 1.39
  • Inject adversarial input to break AI coding assistants.
  • Add better logging when using Subrequest Authentication.

Security-relevant changes

  • Add a server-side check for the meta-refresh challenge that makes sure clients have waited for at least 95% of the time that they should.

Fix potential double-spend for challenges

Anubis operates by issuing a challenge and having the client present a solution for that challenge. Challenges are identified by a unique UUID, which is stored in the database.

The problem is that a challenge could potentially be used twice by a dedicated attacker making a targeted attack against Anubis. Challenge records did not have a "spent" or "used" field. In total, a dedicated attacker could solve a challenge once and reuse that solution across multiple sessions in order to mint additional tokens.

This was fixed by adding a "spent" field to challenges in the data store. When a challenge is solved, that "spent" field gets set to true. If a future attempt to solve this challenge is observed, it gets rejected.

With the advent of store based challenge issuance in #749, this means that these challenge IDs are only good for 30 minutes. Websites using the most recent version of Anubis have limited exposure to this problem.

Websites using older versions of Anubis have a much more increased exposure to this problem and are encouraged to keep this software updated as often and as frequently as possible.

Thanks to @taviso for reporting this issue.

Breaking changes

  • The "slow" frontend solver has been removed in order to reduce maintenance burden. Any existing uses of it will still work, but issue a warning upon startup asking administrators to upgrade to the "fast" frontend solver.
  • The legacy JSON based policy file example has been removed and all documentation for how to write a policy file in JSON has been deleted. JSON based policy files will still work, but YAML is the superior option for Anubis configuration.

New Locales

What's Changed

  • build(deps): bump on-headers and compression in /docs by @dependabot[bot] in #910
  • chore: expose thoth in lib by @Xe in #911
  • test(lib): add a test for the X-Forwarded-For middleware by @Xe in #912
  • build(deps): bump brace-expansion from 1.1.11 to 1.1.12 in /docs by @dependabot[bot] in #909
  • test: add automated Pale Moon tests by @Xe in #903
  • feat(expressions): add segments function to break path into segments by @Xe in #916
  • feat(default-rules): add weight to Custom-AsyncHttpClient by @Xe in #914
  • build(deps): bump the github-actions group with 2 updates by @dependabot[bot] in #929
  • fix(anubis): store the challenge method in the store by @Xe in #924
  • build(deps): bump the gomod group in #931
  • Update is.json by @sveinki in #935
  • fix: polish Turkish translations by @bitigchi in #897
  • fix(lib): add the ability to set a custom slog Logger by @Xe in #915
  • fix: allow social preview images by @Xe in #934
  • refactor(web): redo proof of work web worker logic by @Xe in #941
  • Add HackLab.TO to known instances by @lillian-b in #936
  • fix(web/sha256-browserjs): fix function name by @Xe in #943
  • Add swedish local by @axellse in #913
  • docs: remove JSON examples from policy file docs by @Xe in #945
  • fix(internal): silence unsolicited response log lines by @Xe in #950
  • fix(web): embed challenge ID in pass-challenge invocations by @Xe in #944
  • build(deps): bump the github-actions group with 2 updates by @dependabot[bot] in #952
  • Revert "build(deps): bump the github-actions group with 2 updates" by @JasonLovesDoggo in #962
  • Fix capitalisation in bokmål and nynorsk translations by @turtlegarden in #959
  • Added Dutch translation by @SecularSteve in #937
  • fix(localization): Improve Czech language translation by @Medvidek77 in #895
  • feat(checker): allow png/gif/jpg/jpeg...
Read more

v1.22.0-pre2: Yda Hext

03 Sep 01:35
@Xe Xe

Choose a tag to compare

Pre-release

Full release notes will be written later. This prerelease is meant to help test the new features. Read the changelog for a comprehensive list of changes. It's a lot.

Please file bugs if you encounter issues.

If no major issues are found in the next few days, this ships.

What's Changed

  • s/Wordpress/WordPress in docs by @bradp in #1020
  • docs: fix "stored" typo in CHANGELOG.md by @Krinkle in #1008
  • lib/checker: Implement X-Original-URI support by @samip5 in #1015
  • Add XOriginal to allowed words by @JasonLovesDoggo in #1031
  • build(deps-dev): bump the npm group across 1 directory with 3 updates by @dependabot[bot] in #1032
  • fix(worker): constrain nonce value to be a whole integer by @Xe in #1045
  • fix: middleware traefik redirect url by @phoval in #1040
  • docs(blog): add post about the odd CPU core count bug by @Xe in #1058
  • docs: Fix broken link by @phuzion in #1059
  • Allow to disable keep-alive for the targets not supporting it properly by @samm-git in #1049
  • Alienbob: add Slackware URLs that are now protected by Anubis by @alienbob in #1051
  • docs: document client IP headers and interop with cloudflare by @TinyServal in #1034
  • Update nginx.mdx - needs port_in_redirect off setting by @own3mall in #1018
  • internal/log: Implement logging of HOST when using subrequest auth by @samip5 in #1027
  • feat: add 'proof of React' challenge by @Xe in #1038
  • add Lithuanian locale by @rimas-kudelis in #998
  • chore: introduce issue templates by @Xe in #939
  • feat(localization): Add Vietnamese translation by @ninfia in #926
  • fix(challenge/metarefresh): ensure that clients have waited long enough by @Xe in #1068
  • ci: fix tests by @Xe in #1069
  • chore: break AI agents in this code tree by @Xe in #1065

New Contributors

Full Changelog: v1.22.0-pre1...v1.22.0-pre2

v1.22.0-pre1: Yda Hext

24 Aug 02:45
@Xe Xe

Choose a tag to compare

Pre-release

Full release notes will be written later. This prerelease is meant to help test the new features. Read the changelog for a comprehensive list of changes. It's a lot.

Please file bugs if you encounter issues.

What's Changed

  • build(deps): bump on-headers and compression in /docs by @dependabot[bot] in #910
  • chore: expose thoth in lib by @Xe in #911
  • test(lib): add a test for the X-Forwarded-For middleware by @Xe in #912
  • build(deps): bump brace-expansion from 1.1.11 to 1.1.12 in /docs by @dependabot[bot] in #909
  • test: add automated Pale Moon tests by @Xe in #903
  • feat(expressions): add segments function to break path into segments by @Xe in #916
  • feat(default-rules): add weight to Custom-AsyncHttpClient by @Xe in #914
  • build(deps): bump the github-actions group with 2 updates by @dependabot[bot] in #929
  • fix(anubis): store the challenge method in the store by @Xe in #924
  • build(deps): bump the gomod group in #931
  • Update is.json by @sveinki in #935
  • fix: polish Turkish translations by @bitigchi in #897
  • fix(lib): add the ability to set a custom slog Logger by @Xe in #915
  • fix: allow social preview images by @Xe in #934
  • refactor(web): redo proof of work web worker logic by @Xe in #941
  • Add HackLab.TO to known instances by @lillian-b in #936
  • fix(web/sha256-browserjs): fix function name by @Xe in #943
  • Add swedish local by @axellse in #913
  • docs: remove JSON examples from policy file docs by @Xe in #945
  • fix(internal): silence unsolicited response log lines by @Xe in #950
  • fix(web): embed challenge ID in pass-challenge invocations by @Xe in #944
  • build(deps): bump the github-actions group with 2 updates by @dependabot[bot] in #952
  • Revert "build(deps): bump the github-actions group with 2 updates" by @JasonLovesDoggo in #962
  • Fix capitalisation in bokmål and nynorsk translations by @turtlegarden in #959
  • Added Dutch translation by @SecularSteve in #937
  • fix(localization): Improve Czech language translation by @Medvidek77 in #895
  • feat(checker): allow png/gif/jpg/jpeg/svg favicons as well as ico by @arcayr in #961
  • default pattern fixes by @arcayr in #963
  • feat: support HTTP redirect for forward authentication middleware in Traefik by @phoval in #368
  • Update known-instances.md: add lab.civicrm.org by @mlutfy in #971
  • feat(lib): Add optional restrictions for JWT based on a specific header value by @Earl0fPudding in #697
  • add Lithuanian locale by @rimas-kudelis in #972
  • fix(locales): remove the word "hack" from the description of Anubis by @Xe in #973
  • feat(web): Add option for customizable explanation text by @Earl0fPudding in #747
  • Bump ai.robots.txt to v1.39 by @Dryusdan in #982
  • feat(blog): add short funding update post by @Xe in #994
  • fix(lib): ensure issued challenges don't get double-spent by @Xe in #1003
  • fix(default-config): block Huawei Cloud by @Xe in #1004
  • fix(default-config): also block alibaba cloud by @Xe in #1005
  • Update installation.mdx to include a link to the Caddy docs by @juliankrieger in #993

New Contributors

Full Changelog: v1.21.3...v1.22.0-pre1

v1.21.3: Minfilia Warde - Echo 3

25 Jul 14:36
@Xe Xe

Choose a tag to compare

Fixes GHSA-jhjj-2g64-px7c

This could allow an attacker to craft an Anubis pass-challenge URL that forces a redirect to nonstandard URLs, such as the javascript: scheme which executes arbitrary JavaScript code in a browser context when the user clicks the "Try again" button.

This has been fixed by disallowing any URLs without the scheme http or https.

Additionally, the "Try again" button has been fixed to completely ignore the user-supplied redirect location. It now redirects to the home page (/).

Notes

An incomplete version of this fix was tagged at v1.21.2 and then the release process was aborted upon final testing. Do not package or use v1.21.2.

What's Changed

  • fix(lib): add comprehensive XSS protection logic by @Xe in #905
  • fix(web): make the try again button always go back to / by @Xe in #907

Full Changelog: v1.21.2...v1.21.3

v1.21.1: Minfilia Warde - Echo 1

22 Jul 20:42
@Xe Xe
1a19d7e

Choose a tag to compare

  • Expired records are now properly removed from bbolt databases (#848).
  • Fix hanging on service restart (#853)

Added

Anubis now supports the missingHeader to assert the absence of headers in requests.

New locales

Anubis now supports these new languages:

Fixes

Fix "error: can't get challenge" when details about a challenge can't be found in the server side state

v1.21.0 changed the core challenge flow to maintain information about challenges on the server side instead of only doing them via stateless idempotent generation functions and relying on details to not change. There was a subtle bug introduced in this change: if a client has an unknown challenge ID set in its test cookie, Anubis will clear that cookie and then throw an HTTP 500 error.

This has been fixed by making Anubis throw a new challenge page instead.

Fix event loop thrashing when solving a proof of work challenge

Previously the "fast" proof of work solver had a fragment of JavaScript that attempted to only post an update about proof of work progress to the main browser window every 1024 iterations. This fragment of JavaScript was subtly incorrect in a way that passed review but actually made the workers send an update back to the main thread every iteration. This caused a pileup of unhandled async calls (similar to a socket accept() backlog pileup in Unix) that caused stack space exhaustion.

This has been fixed in the following ways:

  1. The complicated boolean logic has been totally removed in favour of a worker-local iteration counter.
  2. The progress bar is updated by worker 0 instead of all workers.

Hopefully this should limit the event loop thrashing and let ia32 browsers (as well as any environment with a smaller stack size than amd64 and aarch64 seem to have) function normally when processing Anubis proof of work challenges.

Fix potential memory leak when discovering a solution

In some cases, the parallel solution finder in Anubis could cause all of the worker promises to leak due to the fact the promises were being improperly terminated. This was fixed by having Anubis debounce worker termination instead of allowing it to potentially recurse infinitely.

What's Changed

  • docs(known-instances): update list of known instances by @lotharsm in #847
  • fix(cmd/anubis): add signal handling to metrics server by @EmRowlands in #856
  • test: add i18n smoke test by @Xe in #858
  • test(ssh-ci): deflake SSH CI with exponential backoff by @Xe in #859
  • Fix broken BBolt database cleanup process by @thenickdude in #848
  • fix(localization): untranslated string in Filipino language by @hankskyjames777 in #850
  • feat(localization): Add Czech language translation by @xmorave2 in #849
  • feat(expressions): add missingHeader function to bot environment by @Xe in #870
  • build(deps): bump the github-actions group with 2 updates by @dependabot[bot] in #871
  • build(deps-dev): bump the npm group with 3 updates by @dependabot[bot] in #872
  • build(deps): bump the gomod group with 6 updates by @dependabot[bot] in #873
  • Revert "build(deps): bump the gomod group with 6 updates" by @JasonLovesDoggo in #874
  • Remove duplicated string in Filipino language file by @searinminecraft in #875
  • fix(web): amend future leak on proof of work solution by @Xe in #879
  • fix(web/fast): remove event loop thrashing by @Xe in #880
  • Update pt-BR.json by @HQuest in #878
  • fix(lib): fix challenge issuance logic by @Xe in #881
  • Add Finnish localization by @ZerionSeven in #863
  • feat: Russian localization for Anubis by @Xe in #882
  • feat(localization): Add in Bokmål and Nynorsk translations by @turtlegarden in #855
  • chore: release v1.21.1 by @Xe in #887

New Contributors

Full Changelog: v1.21.0...v1.21.1