Vellum/internal/core
mithral 87c17d4854
Some checks failed
CI / ci (push) Has been cancelled
Make the login limiter correct behind a reverse proxy
ClientIP used r.RemoteAddr and ignored X-Forwarded-For. That was right
about not trusting the header from an untrusted peer, but it is only half
the design: behind a proxy every request arrives from the proxy, so the
limiter key in handlers.go was "<proxy-ip>|<username>" for every client on
the internet. One attacker locked out a username for everyone, an attacker
rotating usernames never hit a limit, and sessions.ip recorded the proxy
so the device list was useless.

- VELLUM_TRUSTED_PROXIES is a CIDR list. X-Forwarded-For is honoured only
  when RemoteAddr is inside it, and the chain is walked right-to-left so
  the first address that is not itself a trusted proxy wins. Everything to
  its left was appended by a client we do not control, so a spoofed
  leftmost entry is discarded.
- VELLUM_PUBLIC_URL is the external origin. CookieSecure now defaults to
  true when it is https://, so a TLS deployment that forgets
  VELLUM_COOKIE_SECURE no longer ships a plaintext session cookie.
- A malformed CIDR fails the boot rather than being skipped: silently
  dropping a proxy network widens the trust boundary, which is the exact
  failure this setting exists to prevent.

ClientIP became a method on Authenticator so it can see the trusted set,
which is why handlers.go and main.go changed as well.

Verified red-green: neutering the trusted-peer path fails five ClientIP
tests, including the spoofed-leftmost case.

Known gap, pre-existing and not fixed here: this limiter still covers only
/api/v1/auth/login. Jellyfin AuthenticateByName and Subsonic auth call
auth.Authenticate with no limiting, so the same brute force is available
through those two surfaces.
2026-10-12 00:45:27 -04:00
..
config.go Make the login limiter correct behind a reverse proxy 2026-10-12 00:45:27 -04:00
config_test.go Make the login limiter correct behind a reverse proxy 2026-10-12 00:45:27 -04:00
db.go Wave 1: survive a real library 2026-10-11 13:10:34 -04:00
logging.go Phase 0: skeleton, config, migrations, health check, container 2026-10-09 16:26:08 -04:00
migrate.go Refuse to start when the database is newer than the binary 2026-10-12 00:45:27 -04:00
migrate_test.go Refuse to start when the database is newer than the binary 2026-10-12 00:45:27 -04:00
stamp.go Wave 1: survive a real library 2026-10-11 13:10:34 -04:00
stamp_test.go Wave 1: survive a real library 2026-10-11 13:10:34 -04:00