From e8e360c8021c6f5cddee94485424ee21b925f1e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=B9=8F?= <2829624376@qq.com> Date: Wed, 15 Jul 2026 03:16:24 +0800 Subject: [PATCH] fix(xai): reject unsafe base URL components --- backend/internal/pkg/xai/oauth.go | 2 +- backend/internal/pkg/xai/oauth_test.go | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/backend/internal/pkg/xai/oauth.go b/backend/internal/pkg/xai/oauth.go index ea837fd78a..3d32bb963d 100644 --- a/backend/internal/pkg/xai/oauth.go +++ b/backend/internal/pkg/xai/oauth.go @@ -306,7 +306,7 @@ func normalizeKnownBaseURLPath(raw string) (string, error) { if parsed.User != nil { return "", errors.New("base URL must not include userinfo") } - if parsed.RawQuery != "" { + if parsed.ForceQuery || parsed.RawQuery != "" { return "", errors.New("base URL must not include a query") } if parsed.Fragment != "" { diff --git a/backend/internal/pkg/xai/oauth_test.go b/backend/internal/pkg/xai/oauth_test.go index a82a26e299..f91b5d4937 100644 --- a/backend/internal/pkg/xai/oauth_test.go +++ b/backend/internal/pkg/xai/oauth_test.go @@ -166,6 +166,14 @@ func TestValidateBaseURLAllowsPublicThirdPartyGrokAPI(t *testing.T) { require.Error(t, err) } +func TestValidateBaseURLsRejectEmptyQueryDelimiter(t *testing.T) { + _, err := ValidateBaseURL("https://grok.example.test/v1?") + require.Error(t, err) + + _, err = ValidateTrustedBaseURL("https://api.x.ai/v1?") + require.Error(t, err) +} + func TestBuildResponsesURLWithValidatorUsesCallerPolicy(t *testing.T) { validator := func(raw string) (string, error) { return urlvalidator.ValidateURLFormat(raw, true) @@ -192,6 +200,7 @@ func TestBuildResponsesURLWithValidatorRejectsBaseURLComponents(t *testing.T) { }{ {name: "userinfo", raw: "https://user:secret@grok.example.test/v1"}, {name: "query", raw: "https://grok.example.test/v1?token=secret"}, + {name: "empty query delimiter", raw: "https://grok.example.test/v1?"}, {name: "fragment", raw: "https://grok.example.test/v1#secret"}, }