@@ -148,6 +148,22 @@ describe('proxy', () => {
148148 expect ( body . errors [ 0 ] . code ) . toBe ( 'proxy_path_mismatch' ) ;
149149 } ) ;
150150
151+ it ( 'does not follow protocol-relative paths' , async ( ) => {
152+ const mockResponse = new Response ( '{}' , { status : 200 } ) ;
153+ mockFetch . mockResolvedValueOnce ( mockResponse ) ;
154+
155+ const request = new Request ( 'https://example.com/__clerk//evil.com/steal' ) ;
156+
157+ await clerkFrontendApiProxy ( request , {
158+ publishableKey : 'pk_test_Y2xlcmsuZXhhbXBsZS5jb20k' ,
159+ secretKey : 'sk_test_xxx' ,
160+ } ) ;
161+
162+ // String concatenation keeps the host as FAPI, not evil.com
163+ const fetchedUrl = new URL ( mockFetch . mock . calls [ 0 ] [ 0 ] as string ) ;
164+ expect ( fetchedUrl . host ) . toBe ( 'frontend-api.clerk.dev' ) ;
165+ } ) ;
166+
151167 it ( 'forwards GET request to FAPI with correct headers' , async ( ) => {
152168 const mockResponse = new Response ( JSON . stringify ( { client : { } } ) , {
153169 status : 200 ,
@@ -525,6 +541,33 @@ describe('proxy', () => {
525541 expect ( response . headers . get ( 'Content-Type' ) ) . toBe ( 'application/javascript' ) ;
526542 } ) ;
527543
544+ it ( 'preserves multiple Set-Cookie headers from FAPI response' , async ( ) => {
545+ const headers = new Headers ( ) ;
546+ headers . append ( 'Set-Cookie' , '__client=abc123; Path=/; HttpOnly; Secure' ) ;
547+ headers . append ( 'Set-Cookie' , '__client_uat=1234567890; Path=/; Secure' ) ;
548+ headers . append ( 'Set-Cookie' , '__session=xyz789; Path=/; HttpOnly; Secure' ) ;
549+ headers . append ( 'Content-Type' , 'application/json' ) ;
550+
551+ const mockResponse = new Response ( JSON . stringify ( { client : { } } ) , {
552+ status : 200 ,
553+ headers,
554+ } ) ;
555+ mockFetch . mockResolvedValue ( mockResponse ) ;
556+
557+ const request = new Request ( 'https://example.com/__clerk/v1/client' ) ;
558+
559+ const response = await clerkFrontendApiProxy ( request , {
560+ publishableKey : 'pk_test_Y2xlcmsuZXhhbXBsZS5jb20k' ,
561+ secretKey : 'sk_test_xxx' ,
562+ } ) ;
563+
564+ const setCookies = response . headers . getSetCookie ( ) ;
565+ expect ( setCookies ) . toHaveLength ( 3 ) ;
566+ expect ( setCookies ) . toContain ( '__client=abc123; Path=/; HttpOnly; Secure' ) ;
567+ expect ( setCookies ) . toContain ( '__client_uat=1234567890; Path=/; Secure' ) ;
568+ expect ( setCookies ) . toContain ( '__session=xyz789; Path=/; HttpOnly; Secure' ) ;
569+ } ) ;
570+
528571 it ( 'preserves relative Location headers' , async ( ) => {
529572 const mockResponse = new Response ( null , {
530573 status : 302 ,
0 commit comments