Skip to content

Release v2.11.4

Choose a tag to compare

@github-actions github-actions released this 05 Aug 14:27
82bd497

Summary

Hardens what a deployment can declare as an anonymous path, fixes four security defects found while doing so, and adds a security spec suite that gates every pull request.

The anonymous path rules moved from a deny-list of route-template characters to an allow-list of RFC 3986 unreserved characters. A deny-list has to anticipate every character that means something to one of the two matchers — the middlewares matching a literal and the router matching a route template — and the cost of missing one is a prefix that means different things to each. Refusals stay fail-closed, leaving the path authenticated, and are now reported at startup instead of being silent.

Added

  • Security spec suite covering broken access control, injection, open redirect, request smuggling and security misconfiguration. Specs run a real AuthProxy in front of a real origin that records every forwarded request, so assertions can be made about what reached the backend rather than only what the client saw (#42)
  • A Security workflow that runs the security specs and a known-vulnerable dependency check on every pull request, with no path filter (#42)
  • Startup warnings naming every declared anonymous path that was refused, and why

Changed

  • Anonymous path entries are validated against an allow-list of letters, digits, -, ., _ and ~. Percent-encoding, backslashes, semicolons, authority syntax, control characters and non-ASCII are refused, as is any . or .. segment
  • Anonymous path entries may no longer target the prefixes AuthProxy answers itself (/.cratis, /_pages, /invite, /register, /signin-*). Declaring one never made an endpoint more public — it took the endpoint away from AuthProxy and handed it to a backend
  • CI now builds Debug as well as Release and runs the specs. Previously no tests ran in CI at all

Security

  • Fixed an open redirect on the login, link, tenant-selection and logout endpoints. Each carried its own version of a same-site check and they disagreed: two accepted //evil.test outright, and the two that rejected it still accepted /\evil.test, which every major browser treats identically. The login endpoint is the most exposed of the four — its returnUrl is accepted anonymously and becomes the post-authentication redirect, so a victim completes a genuine sign-in before landing on the attacker's page
  • Fixed authorization being granted by the presence of the script-readable .cratis-identity cookie, whose value was never read. Sending any value for it alongside a valid session skipped every service's /.cratis/me authorization call, so a user whose access had been revoked stayed authorized for as long as they kept sending it. The decision now lives in a separate HTTP-only cookie sealed with data protection and bound to the principal and tenant it was issued for
  • Fixed an unauthenticated HTTP 500 reachable by sending both a Service-ID header and a ?service= parameter. The two route variants shared a template and an order, and endpoint selection runs ahead of authentication