This is based on private evaluation of a prerelease security product.
I cannot comment further other than I am impressed by its output.
This commit is a squash of several commits. The impactful commits
have details underneath markdown heading twos.
## fix(metrics): don't expose pprof by default
pprof[1] is the Go standard library profiling toolkit. It is invaluable
for diagnosing how Go programs perform in the wild. However it also is
able to expose secret data set with command line flags. This is not
ideal and should be mitigated by correctly configured firewall rules. We
don't live in a world where people correctly configure firewall rules,
so we have to fix things for people. Welcome to 2026.
[1]: https://pkg.go.dev/runtime/pprof
Ref: AWOO-001
## fix(honeypot/naive): cap r9k delay to one second
Otherwise this can get unbounded, which can cause problems with lesser
HTTP proxies such as Apache.
Ref: AWOO-002
## fix(policy): mend an edge case with subrequest auth and query strings
This fixes an unlikely edge case where using subrequest auth and query
strings with path based filtering can cause reality to differ from
administrator intent. This effectively strips the query string from
subrequest auth checks. This deficiency should be fixed in the future.
Ref: AWOO-004
## fix(expressions): mend possible nil pointer deref edge case
If Anubis just started up, load averages may not be set in memory. This
can cause a nil pointer dereference which could fail requests with weird
errors until the async thread sets the load averages.
Ref: AWOO-005
## fix(lib): mend case where domainless redirects could allow cross-domain redirects
Ref: AWOO-009
## fix(expressions): validate randInt bounds before rand.IntN
Non-positive or platform-overflowing arguments to the CEL randInt
helper used to reach rand.IntN unchecked, surfacing a CEL evaluator
error during request processing when policies passed
attacker-influenced values (e.g. contentLength). Reject non-positive
bounds and detect int narrowing explicitly, returning a typed CEL
error in both cases.
Ref: AWOO-010
Signed-off-by: Xe Iaso <[email protected]>
* fix(policy): correctly wire subrequest mode through CEL/path checkers
Previously Anubis only checked for the X-Original-Url when using
subrequest mode. This header is used by the example nginx config to pass
the request path through from the original client request to Anubis in
order to do path-based filtering.
According to facts and circumstances, Traefik hardcodes its own
headers[1]:
```text
httpdebug-1 | GET /.within.website/x/cmd/anubis/api/check
httpdebug-1 | X-Forwarded-Method: GET
httpdebug-1 | X-Forwarded-Proto: http
httpdebug-1 | X-Forwarded-Server: b9a5d299c929
httpdebug-1 | X-Forwarded-Port: 8080
httpdebug-1 | X-Forwarded-Uri: /
httpdebug-1 | X-Real-Ip: 172.18.0.1
httpdebug-1 | Accept-Encoding: gzip
httpdebug-1 | User-Agent: curl/8.20.0
httpdebug-1 | Accept: */*
httpdebug-1 | X-Forwarded-For: 172.18.0.1
httpdebug-1 | X-Forwarded-Host: localhost:8080
```
As a result, this means that path-based filtering did not work.
This commit fixes this issue by amending how path based checking logic
works:
* For CEL based checks, this pipes through the `subrequestMode` flag from
main and alters the behaviour if either `X-Original-Url` or
`X-Forwarded-Url` are found. These values are currently hardcoded for
convenience but probably need to be made configurable in the policy
file at a future date.
* For path-based checks, this uses the existing `subrequestMode` flag
from main and adds `X-Forwarded-Url` to the list of headers it checks.
A smoke test was added to make sure that traefik in this mode continues
to work. Thank you https://github.com/flifloo for filing a detailed
issue with the relevant configuration fragments. Those configuration
fragments formed the core of this smoke test.
[1]: https://doc.traefik.io/traefik/v3.4/middlewares/http/forwardauth/
Closes: https://github.com/TecharoHQ/anubis/issues/1628
Signed-off-by: Xe Iaso <[email protected]>
Co-Authored-By: flifloo <[email protected]>
* chore: spelling
Signed-off-by: Xe Iaso <[email protected]>
---------
Signed-off-by: Xe Iaso <[email protected]>
Co-authored-by: flifloo <[email protected]>
* fix: patch GHSA-6wcg-mqvh-fcvg
PR https://github.com/TecharoHQ/anubis/pull/1015 added the ability for
reverse proxies using Anubis in subrequest auth mode to look at the path
of a request as there are many rules in the wild that rely on checking
the path. This is how access to things like robots.txt or anything in the
.well-known directory is unaffected by Anubis.
However this logic was also enabled for non-subrequest deployments of Anubis,
meaning that a specially crafted request could include a /.well-known/
path in it and then get around Anubis with little effort.
This fix gates the logic behind a new plumbed variable named subrequestMode
that only fires when Anubis is running in subrequest auth mode. This
properly contains that workaround so that the logic does not fire in
most deployments.
Signed-off-by: Xe Iaso <[email protected]>
* chore: spelling
Signed-off-by: Xe Iaso <[email protected]>
---------
Signed-off-by: Xe Iaso <[email protected]>
* fix: enable CEL iterators
Signed-off-by: Jason Cameron <[email protected]>
* test: add unit tests for CELChecker map iteration
Signed-off-by: Jason Cameron <[email protected]>
* fix: implement map iterators for HTTPHeaders and URLValues to resolve CEL internal errors
Signed-off-by: Jason Cameron <[email protected]>
* fix: replace checker.NewMapIterator with newMapIterator for HTTPHeaders and URLValues
Signed-off-by: Jason Cameron <[email protected]>
---------
Signed-off-by: Jason Cameron <[email protected]>
* feat: first implementation of honeypot logic
This is a bit of an experiment, stick with me.
The core idea here is that badly written crawlers are that: badly
written. They look for anything that contains `<a href="whatever" />`
tags and will blindly use those values to recurse. This takes advantage
of that by hiding a link in a `<script>` tag like this:
```html
<script type="ignore"><a href="/bots-only">Don't click</a></script>
```
Browsers will ignore it because they have no handler for the "ignore"
script type.
This current draft is very unoptimized (it takes like 7 seconds to
generate a page on my tower), however switching spintax libraries will
make this much faster.
The hope is to make this pluggable with WebAssembly such that we force
administrators to choose a storage method. First we crawl before we
walk.
The AI involvement in this commit is limited to the spintax in
affirmations.txt, spintext.txt, and titles.txt. This generates a bunch
of "pseudoprofound bullshit" like the following:
> This Restoration to Balance & Alignment
>
> There's a moment when creators are being called to realize that the work
> can't be reduced to results, but about energy. We don't innovate products
> by pushing harder, we do it by holding the vision. Because momentum can't
> be forced, it unfolds over time when culture are moving in the same
> direction. We're being invited into a paradigm shift in how we think
> about innovation. [...]
This is intended to "look" like normal article text. As this is a first
draft, this sucks and will be improved upon.
Assisted-by: GLM 4.6, ChatGPT, GPT-OSS 120b
Signed-off-by: Xe Iaso <[email protected]>
* fix(honeypot/naive): optimize hilariously
Signed-off-by: Xe Iaso <[email protected]>
* feat(honeypot/naive): attempt to automatically filter out based on crawling
Signed-off-by: Xe Iaso <[email protected]>
* fix(lib): use mazeGen instead of bsGen
Signed-off-by: Xe Iaso <[email protected]>
* docs: add honeypot docs
Signed-off-by: Xe Iaso <[email protected]>
* chore(test): go mod tidy
Signed-off-by: Xe Iaso <[email protected]>
* chore: fix spelling metadata
Signed-off-by: Xe Iaso <[email protected]>
* chore: spelling
Signed-off-by: Xe Iaso <[email protected]>
---------
Signed-off-by: Xe Iaso <[email protected]>
* Implement FCrDNS and other DNS features
* Redesign DNS cache and methods
* Fix DNS cache
* Rename regexSafe arg
* Alter verifyFCrDNS(addr) behaviour
* Remove unused dnsCache field from Server struct
* Upd expressions docs
* Update docs/docs/CHANGELOG.md
Signed-off-by: Xe Iaso <[email protected]>
* refactor(dns): simplify FCrDNS logging
* docs: clarify verifyFCrDNS behavior
Add a note to the documentation for `verifyFCrDNS` to clarify that it returns true when no PTR records are found for the given IP address.
* fix(dns): Improve FCrDNS error handling and tests
The `VerifyFCrDNS` function previously ignored errors returned from reverse DNS lookups. This could lead to incorrect passes when a DNS failure (other than a simple 'not found') occurred. This change ensures that any error from a reverse lookup will cause the FCrDNS check to fail.
The test suite for FCrDNS has been updated to reflect this change. The mock DNS lookups now simulate both 'not found' errors and other generic DNS errors. The test cases have been updated to ensure that the function behaves correctly in both scenarios, resolving a situation where two test cases were effectively duplicates.
* docs: Update FCrDNS documentation and spelling
Corrected a typo in the `verifyFCrDNS` function documentation.
Additionally, updated the spelling exception list to include new terms and remove redundant entries.
* chore: update spelling
Signed-off-by: Xe Iaso <[email protected]>
---------
Signed-off-by: Xe Iaso <[email protected]>
Co-authored-by: Xe Iaso <[email protected]>
* fix(config): deprecate the report_as field for challenges
This was a bad idea when it was added and it is irresponsible to
continue to have it. It causes more UX problems than it fixes with
slight of hand.
Closes: #1310Closes: #1307
Signed-off-by: Xe Iaso <[email protected]>
* fix(policy): use the new logger for config validation messages
Signed-off-by: Xe Iaso <[email protected]>
* docs(admin/thresholds): remove this report_as setting
Signed-off-by: Xe Iaso <[email protected]>
---------
Signed-off-by: Xe Iaso <[email protected]>
* fix!(policy/checker): make List and-like
This has the potential to break user configs.
Anubis lets you stack multiple checks at once with blocks like this:
```yaml
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 have marked this as a potentially breaking change because I'm
absolutely certain that someone is relying on this behaviour due to
spacebar heating. If this bites you, please let me know ASAP.
Signed-off-by: Xe Iaso <[email protected]>
Assisted-by: GPT-OSS 120b on local hardware
* fix(policy/checker): more explicit short-circuit
Signed-off-by: Xe Iaso <[email protected]>
---------
Signed-off-by: Xe Iaso <[email protected]>
* refactor: make challenge pages return the challenge component
This means that challenge pages will return only the little bit that
actually matters, not the entire component.
Signed-off-by: Xe Iaso <[email protected]>
* fix(web): move Anubis version info to be implicitly in the footer
Signed-off-by: Xe Iaso <[email protected]>
* fix(web): embed challenge ID into generated pages
Signed-off-by: Xe Iaso <[email protected]>
* fix(lib): make tests pass
Signed-off-by: Xe Iaso <[email protected]>
* test(lib/policy/config): amend tests
Signed-off-by: Xe Iaso <[email protected]>
* test(lib): fix tests again
Signed-off-by: Xe Iaso <[email protected]>
---------
Signed-off-by: Xe Iaso <[email protected]>
Signed-off-by: Xe Iaso <[email protected]>
* chore(web/js): delete proof-of-work-slow.mjs
This code has served its purpose and now needs to be retired to the
great beyond. There is no replacement for this, the fast implementation
will be used instead.
Signed-off-by: Xe Iaso <[email protected]>
* chore(web): handle building multiple JS entrypoints and web workers
Signed-off-by: Xe Iaso <[email protected]>
* feat(web): rewrite frontend worker handling
This completely rewrites how the proof of work challenge works based on
feedback from browser engine developers and starts the process of making
the proof of work function easier to change out.
- Import @aws-crypto/sha256-js to use in Firefox as its implementation
of WebCrypto doesn't jump directly from highly optimized browser
internals to JIT-ed JavaScript like Chrome's seems to.
- Move the worker code to `web/js/worker/*` with each worker named after
the hashing method and hash method implementation it uses.
- Update bench.mjs to import algorithms the new way.
- Delete video.mjs, it was part of a legacy experiment that I never had
time to finish.
- Update LibreJS comment to add info about the use of
@aws-crypto/sha256-js.
- Also update my email to my @techaro.lol address.
Signed-off-by: Xe Iaso <[email protected]>
* fix(web): don't hard dep webcrypto anymore
Signed-off-by: Xe Iaso <[email protected]>
* chore(lib/policy): start the deprecation process for slow
This mostly adds a warning, but the "slow" method is in the process of
being removed. Warn admins with slog.Warn.
Signed-off-by: Xe Iaso <[email protected]>
* docs: update CHANGELOG
Signed-off-by: Xe Iaso <[email protected]>
* feat(web/js): allow running Anubis in non-secure contexts
Signed-off-by: Xe Iaso <[email protected]>
* Update metadata
check-spelling run (pull_request) for Xe/purge-slow
Signed-off-by: check-spelling-bot <[email protected]>
on-behalf-of: @check-spelling <[email protected]>
---------
Signed-off-by: Xe Iaso <[email protected]>
Signed-off-by: check-spelling-bot <[email protected]>
* feat(lib/policy/expressions): add system load average to bot expression inputs
This lets Anubis dynamically react to system load in order to
increase and decrease the required level of scrutiny. High load? More
scrutiny required. Low load? Less scrutiny required.
* docs: spell system correctly
Signed-off-by: Xe Iaso <[email protected]>
* Update metadata
check-spelling run (pull_request) for Xe/load-average
Signed-off-by: check-spelling-bot <[email protected]>
on-behalf-of: @check-spelling <[email protected]>
* fix(default-config): don't enable low load average feature by default
Signed-off-by: Xe Iaso <[email protected]>
---------
Signed-off-by: Xe Iaso <[email protected]>
Signed-off-by: check-spelling-bot <[email protected]>
Signed-off-by: Xe Iaso <[email protected]>
* feat(decaymap): add Delete method
Signed-off-by: Xe Iaso <[email protected]>
* chore(lib/challenge): refactor Validate to take ValidateInput
Signed-off-by: Xe Iaso <[email protected]>
* feat(lib): implement store interface
Signed-off-by: Xe Iaso <[email protected]>
* feat(lib/store): all metapackage to import all store implementations
Signed-off-by: Xe Iaso <[email protected]>
* chore(policy): import all store backends
Signed-off-by: Xe Iaso <[email protected]>
* feat(lib): use new challenge creation flow
Previously Anubis constructed challenge strings from request metadata.
This was a good idea in spirit, but has turned out to be a very bad idea
in practice. This new flow reuses the Store facility to dynamically
create challenge values with completely random data.
This is a fairly big rewrite of how Anubis processes challenges. Right
now it defaults to using the in-memory storage backend, but on-disk
(boltdb) and valkey-based adaptors will come soon.
Signed-off-by: Xe Iaso <[email protected]>
* chore(decaymap): fix documentation typo
Signed-off-by: Xe Iaso <[email protected]>
* chore(lib): fix SA4004
Signed-off-by: Xe Iaso <[email protected]>
* test(lib/store): make generic storage interface test adaptor
Signed-off-by: Xe Iaso <[email protected]>
* chore: spelling
Signed-off-by: Xe Iaso <[email protected]>
* fix(decaymap): invert locking process for Delete
Signed-off-by: Xe Iaso <[email protected]>
* feat(lib/store): add bbolt store implementation
Signed-off-by: Xe Iaso <[email protected]>
* chore: spelling
Signed-off-by: Xe Iaso <[email protected]>
* chore: go mod tidy
Signed-off-by: Xe Iaso <[email protected]>
* chore(devcontainer): adapt to docker compose, add valkey service
Signed-off-by: Xe Iaso <[email protected]>
* fix(lib): make challenges live for 30 minutes by default
Signed-off-by: Xe Iaso <[email protected]>
* feat(lib/store): implement valkey backend
Signed-off-by: Xe Iaso <[email protected]>
* test(lib/store/valkey): disable tests if not using docker
Signed-off-by: Xe Iaso <[email protected]>
* test(lib/policy/config): ensure valkey stores can be loaded
Signed-off-by: Xe Iaso <[email protected]>
* Update metadata
check-spelling run (pull_request) for Xe/store-interface
Signed-off-by: check-spelling-bot <[email protected]>
on-behalf-of: @check-spelling <[email protected]>
* chore(devcontainer): remove port forwards because vs code handles that for you
Signed-off-by: Xe Iaso <[email protected]>
* docs(default-config): add a nudge to the storage backends section of the docs
Signed-off-by: Xe Iaso <[email protected]>
* chore(docs): listen on 0.0.0.0 for dev container support
Signed-off-by: Xe Iaso <[email protected]>
* docs(policy): document storage backends
Signed-off-by: Xe Iaso <[email protected]>
* docs: update CHANGELOG and internal links
Signed-off-by: Xe Iaso <[email protected]>
* docs(admin/policies): don't start a sentence with as
Signed-off-by: Xe Iaso <[email protected]>
* chore: fixes found in review
Signed-off-by: Xe Iaso <[email protected]>
---------
Signed-off-by: Xe Iaso <[email protected]>
Signed-off-by: check-spelling-bot <[email protected]>
* chore(xess): remove unused xess templates
Signed-off-by: Jason Cameron <[email protected]>
* chore(checker): remove unused staticHashChecker implementation
Signed-off-by: Jason Cameron <[email protected]>
* feat: add pinact and deadcode to go tools (pinact is used for the gha pinning)
Signed-off-by: Jason Cameron <[email protected]>
* chore: update Docker and kubectl actions to latest versions
Signed-off-by: Jason Cameron <[email protected]>
* chore: update Homebrew action from master to main in workflow files
See https://github.com/Homebrew/actions/commit/df537ec97fb77a615dc06a860b3d5b6d9c256cdb
Signed-off-by: Jason Cameron <[email protected]>
* chore: remove unused go-colorable and tools dependencies from go.sum
Signed-off-by: Jason Cameron <[email protected]>
* chore: update postcss-import and other dependencies to latest versions
Signed-off-by: Jason Cameron <[email protected]>
* chore: update Docusaurus dependencies to version 3.8.1
Signed-off-by: Jason Cameron <[email protected]>
* chore: downgrade playwright and playwright-core to version 1.52.0
Signed-off-by: Jason Cameron <[email protected]>
---------
Signed-off-by: Jason Cameron <[email protected]>
* feat: replace cidranger with bart improving performance by 3-20x
Signed-off-by: Jason Cameron <[email protected]>
* perf: replace cidranger with bart for IP range checking
- Replace cidranger.Ranger with bart.Lite in RemoteAddrChecker
- Use netip.ParsePrefix instead of net.ParseCIDR for modern IP handling
- Improve performance: 3-20x faster lookups with zero heap allocations
- Update imports to use github.com/gaissmai/bart and net/netip
- Remove cidranger dependency from go.mod
Benchmark results:
- IPv4 lookups: 4x faster (15.58ns vs 63.25ns, 0 vs 2 allocs)
- IPv6 lookups: 3x faster (26.51ns vs 76.96ns, 0 vs 2 allocs)
- Insertions: 20x faster (976ns vs 19,191ns)
- Large tables: 14x faster (5.2ns vs 74.85ns)
* docs: clarify CHANGELOG to not give false impressions
Signed-off-by: Jason Cameron <[email protected]>
* perf: optimize string concatenation in RemoteAddrChecker hash generation
Replace fmt.Fprintln with strings.Join for 7x faster performance:
- Before: 935.1 ns/op, 784 B/op, 22 allocs/op
- After: 133.2 ns/op, 192 B/op, 1 alloc/op
The hash is used for JWT cookie validation and error code generation.
Comma separation provides the same deterministic uniqueness as newlines
but with significantly better performance during policy initialization.
* chore: remove accidentally commited string benchmark
Signed-off-by: Jason Cameron <[email protected]>
* style: apply Copilot suggestions
Signed-off-by: Jason Cameron <[email protected]>
* fix: reference the right var name
i cannot write a merge commit
Signed-off-by: Jason Cameron <[email protected]>
---------
Signed-off-by: Jason Cameron <[email protected]>
* style: fix formatting in .air.toml and installation.mdx
* feat: add --strip-base-prefix flag to modify request paths when forwarding
Closes: #638
* refactor: apply structpacking (betteralign)
* fix: add validation for strip-base-prefix and base-prefix configuration
* fix: improve request path handling by cloning request and modifying URL path
* chore: remove integration tests as they are too annoying to debug on my system
* feat(lib): implement request weight
Replaces #608
This is a big one and will be what makes Anubis a generic web
application firewall. This introduces the WEIGH option, allowing
administrators to have facets of request metadata add or remove
"weight", or the level of suspicion. This really makes Anubis weigh
the soul of requests.
Signed-off-by: Xe Iaso <[email protected]>
* fix(lib): maintain legacy challenge behavior
Signed-off-by: Xe Iaso <[email protected]>
* fix(lib): make weight have dedicated checkers for the hashes
Signed-off-by: Xe Iaso <[email protected]>
* feat(data): convert some rules over to weight points
Signed-off-by: Xe Iaso <[email protected]>
* docs: document request weight
Signed-off-by: Xe Iaso <[email protected]>
* fix(CHANGELOG): spelling error
Signed-off-by: Xe Iaso <[email protected]>
* chore: spelling
Signed-off-by: Xe Iaso <[email protected]>
* docs: fix links to challenge information
Signed-off-by: Xe Iaso <[email protected]>
* docs(policies): fix formatting
Signed-off-by: Xe Iaso <[email protected]>
* fix(config): make default weight adjustment 5
Signed-off-by: Xe Iaso <[email protected]>
---------
Signed-off-by: Xe Iaso <[email protected]>
* chore(deps): update dependencies in go.mod and go.sum
Signed-off-by: Jason Cameron <[email protected]>
* refactor: rename variables for clarity in anubis.go and main.go
Signed-off-by: Jason Cameron <[email protected]>
* fix(checker): handle error when inserting IP range in ranger
Signed-off-by: Jason Cameron <[email protected]>
* fix(tests): simplify boolean checks in header and URL value tests
Signed-off-by: Jason Cameron <[email protected]>
* refactor(api): remove unused /test-error endpoint and restrict /make-challenge to development
Signed-off-by: Jason Cameron <[email protected]>
* build(deps): update golang-set to v2.8.0 in go.sum
Signed-off-by: Jason Cameron <[email protected]>
* Update metadata
check-spelling run (pull_request) for json/stuff
Signed-off-by: check-spelling-bot <[email protected]>
on-behalf-of: @check-spelling <[email protected]>
---------
Signed-off-by: Jason Cameron <[email protected]>
Signed-off-by: check-spelling-bot <[email protected]>
* Split up AI filtering files
Create aggressive/moderate/permissive policies to allow administrators to choose their AI/LLM stance.
Aggressive policy matches existing default in Anubis.
Removes `Google-Extended` flag from `ai-robots-txt.yaml` as it doesn't exist in requests.
Rename `ai-robots-txt.yaml` to `ai-catchall.yaml` as the file is no longer a copy of the source repo/file.
* chore: spelling
* chore: fix embeds
* chore: fix data includes
* chore: fix file name typo
* chore: Ignore READMEs in configs
* chore(lib/policy/config): go tool goimports -w
Signed-off-by: Xe Iaso <[email protected]>
---------
Signed-off-by: Xe Iaso <[email protected]>
Co-authored-by: Xe Iaso <[email protected]>
This seems counter-intuitive at first glance, but let me cook.
One of the problems with Anubis is that the rule matching is super
deterministic. This means that attackers can figure out what patterns
they are hitting and change things to bypass them.
The randInt function lets you have rulesets behave nondeterministically.
This is a very easy way to hang yourself, but can be great to
psychologically mess with scraper operators. Consider this rule:
```yaml
- name: deny-lightpanda-sometimes
action: DENY
expression:
all:
- userAgent.matches("LightPanda")
- randInt(16) >= 4
```
It would match about 75% of the time.
Signed-off-by: Xe Iaso <[email protected]>
* refactor: reorder import statements in fetch.go and fetch_test.go
Signed-off-by: Jason Cameron <[email protected]>
* fix: optimize struct field alignment to reduce memory usage
Signed-off-by: Jason Cameron <[email protected]>
---------
Signed-off-by: Jason Cameron <[email protected]>
* feat(lib/policy): add support for CEL checkers
This adds the ability for administrators to use Common Expression
Language[0] (CEL) for more advanced check logic than Anubis previously
offered.
These can be as simple as:
```yaml
- name: allow-api-routes
action: ALLOW
expression:
and:
- '!(method == "HEAD" || method == "GET")'
- path.startsWith("/api/")
```
or get as complicated as:
```yaml
- name: allow-git-clients
action: ALLOW
expression:
and:
- userAgent.startsWith("git/") || userAgent.contains("libgit") || userAgent.startsWith("go-git") || userAgent.startsWith("JGit/") || userAgent.startsWith("JGit-")
- >
"Git-Protocol" in headers && headers["Git-Protocol"] == "version=2"
```
Internally these are compiled and evaluated with cel-go[1]. This also
leaves room for extensibility should that be desired in the future. This
will intersect with #338 and eventually intersect with TLS fingerprints
as in #337.
[0]: https://cel.dev/
[1]: https://github.com/google/cel-go
Signed-off-by: Xe Iaso <[email protected]>
* feat(data/apps): add API route allow rule for non-HEAD/GET
Signed-off-by: Xe Iaso <[email protected]>
* docs: document expression syntax
Signed-off-by: Xe Iaso <[email protected]>
* fix: fixes in review
Signed-off-by: Xe Iaso <[email protected]>
---------
Signed-off-by: Xe Iaso <[email protected]>
Closes#372
Fun YAML fact of the day:
What is the difference between how these two expressions are parsed?
```yaml
foo: >
bar
```
```yaml
foo: >-
bar
```
They are invisible in yaml, but when you evaluate them to JSON the
difference is obvious:
```json
{
"foo": "bar\n"
}
```
```json
{
"foo": "bar"
}
```
User-Agent strings, URL path values, and HTTP headers _do_ end in
newlines in HTTP/1.1 wire form, but that newline is usually stripped
before the server actually handles it. Also HTTP/2 is a thing and does
not terminate header values with newlines.
This change makes Anubis more aggressively detect mistaken uses of the
yaml `>` operator and nudges the user into using the yaml `>-` operator
which does not append the trailing newline.
I had honestly forgotten about this YAML behavior because it wasn't
relevant for so long. Oops! Glad I released a beta.
Whenever you get into this state, Anubis will throw a config parsing
error and then give you a message hinting at the folly of your ways.
```
config.Bot: regular expression ends with newline (try >- instead of > in yaml)
```
Big thanks to https://yaml-multiline.info, this helped me realize my
folly instantly.
@aiverson, this is official permission to say "told you so".
Signed-off-by: Xe Iaso <[email protected]>