Fix ForwardAuth fail-open and consent CSRF bypass

Two HIGH-severity findings from the security review:

- ForwardAuth: when no host header was present, /api/verify skipped the
  application lookup and group check entirely, returning 200 with identity
  headers (including all of the user's groups). This bypassed per-domain
  access control. Now fails closed with 403, and the unreachable
  DEFAULT_HEADERS fallback (the bypass path) is removed so headers are
  always scoped to a resolved, active application.

- OIDC: the consent endpoint was in the verify_authenticity_token skip
  list, so a forged cross-site POST could silently grant OAuth scopes.
  Removed :consent from the skip list (the form already embeds the token).

Adds regression tests for both: fail-closed with no identity headers when
host is absent, and 422 on a tokenless consent POST.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Dan Milne
2026-06-11 07:52:56 +10:00
parent 2843790cef
commit 703d24e4e4
4 changed files with 46 additions and 19 deletions

View File

@@ -242,6 +242,20 @@ module Api
assert_equal "No authentication rule configured for this domain", response.headers["x-auth-reason"]
end
# Fail closed when no host can be determined: emitting identity headers without
# an application would bypass all per-domain group access control.
test "should fail closed and emit no identity headers when host is absent" do
sign_in_as(@user)
# Blank both host sources so forwarded_host is not present.
get "/api/verify", headers: {"X-Forwarded-Host" => "", "Host" => ""}
assert_response 403
assert_equal "No host header present", response.headers["x-auth-reason"]
assert_nil response.headers["X-Remote-User"]
assert_nil response.headers["X-Remote-Groups"]
end
# Security Tests
test "should handle very long domain names" do
long_domain = "a" * 250 + ".example.com"