From 31713c324b65c51fce55fc138d43c8e7a95f2156 Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 22 Apr 2026 18:21:40 +0200 Subject: [PATCH] fix(proxy): block proxy-connection hop-by-hop header from client responses Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/routes/api/[...path]/+server.ts | 3 ++- frontend/src/routes/api/[...path]/proxy.spec.ts | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/frontend/src/routes/api/[...path]/+server.ts b/frontend/src/routes/api/[...path]/+server.ts index 887ef530..fa08d455 100644 --- a/frontend/src/routes/api/[...path]/+server.ts +++ b/frontend/src/routes/api/[...path]/+server.ts @@ -12,7 +12,8 @@ const HOP_BY_HOP_HEADERS = new Set([ 'proxy-authenticate', 'proxy-authorization', 'te', - 'trailer' + 'trailer', + 'proxy-connection' ]); async function proxy(event: Parameters[0]): Promise { diff --git a/frontend/src/routes/api/[...path]/proxy.spec.ts b/frontend/src/routes/api/[...path]/proxy.spec.ts index 745134a2..2831794c 100644 --- a/frontend/src/routes/api/[...path]/proxy.spec.ts +++ b/frontend/src/routes/api/[...path]/proxy.spec.ts @@ -167,6 +167,23 @@ describe('catch-all API proxy — forwarding', () => { expect(response.headers.get('Content-Disposition')).toBe('attachment; filename="document.pdf"'); }); + it('does not forward proxy-connection hop-by-hop header', async () => { + const mockFetch = vi.fn().mockResolvedValue( + new Response('data', { + status: 200, + headers: { + 'Content-Type': 'application/json', + 'Proxy-Connection': 'keep-alive' + } + }) + ); + const event = makeEvent('documents', 'GET', mockFetch); + + const response = await GET(event as never); + + expect(response.headers.get('Proxy-Connection')).toBeNull(); + }); + it('does not forward hop-by-hop headers like transfer-encoding', async () => { const mockFetch = vi.fn().mockResolvedValue( new Response('data', {