From c1f16b706e13e4d702cd32f51e9045d80cd32fd7 Mon Sep 17 00:00:00 2001 From: kyinhub Date: Sun, 26 Jul 2026 09:06:59 -0700 Subject: [PATCH] fix(session): reject edge control characters --- sdk/cliproxy/session/identity.go | 8 ++++---- sdk/cliproxy/session/identity_test.go | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/sdk/cliproxy/session/identity.go b/sdk/cliproxy/session/identity.go index 84a3a653c..696e0372a 100644 --- a/sdk/cliproxy/session/identity.go +++ b/sdk/cliproxy/session/identity.go @@ -42,15 +42,15 @@ type canonicalPart struct { // NormalizeExplicitID validates an explicit client-provided session identifier. // It preserves opaque printable values while rejecting oversized or control-bearing IDs. func NormalizeExplicitID(raw string) string { - raw = strings.TrimSpace(raw) - if raw == "" || len(raw) > 256 { - return "" - } for _, r := range raw { if unicode.IsControl(r) { return "" } } + raw = strings.TrimSpace(raw) + if raw == "" || len(raw) > 256 { + return "" + } return raw } diff --git a/sdk/cliproxy/session/identity_test.go b/sdk/cliproxy/session/identity_test.go index a8cad079c..7211d3798 100644 --- a/sdk/cliproxy/session/identity_test.go +++ b/sdk/cliproxy/session/identity_test.go @@ -244,6 +244,14 @@ func TestEnrichDerivesAfterInvalidSessionIdentity(t *testing.T) { name: "oversized prompt cache key", payload: []byte(`{"prompt_cache_key":"` + strings.Repeat("x", 257) + `",` + baseMessages + `}`), }, + { + name: "trailing control character prompt cache key", + payload: []byte(`{"prompt_cache_key":"tenant\n",` + baseMessages + `}`), + }, + { + name: "leading control character prompt cache key", + payload: []byte(`{"prompt_cache_key":"\ttenant",` + baseMessages + `}`), + }, { name: "control character session header", payload: []byte(`{` + baseMessages + `}`),