diff --git a/.changeset/stupid-dancers-relate.md b/.changeset/stupid-dancers-relate.md new file mode 100644 index 000000000..30cffd095 --- /dev/null +++ b/.changeset/stupid-dancers-relate.md @@ -0,0 +1,5 @@ +--- +'@verdaccio/url': patch +--- + +patch(core/url): Throw if VERDACCIO_FORWARDED_PROTO resolves to an array (#4613 by @Tobbe) diff --git a/packages/core/url/src/index.ts b/packages/core/url/src/index.ts index e7dc79942..103f9bd8e 100644 --- a/packages/core/url/src/index.ts +++ b/packages/core/url/src/index.ts @@ -121,10 +121,17 @@ export function getPublicUrl(url_prefix: string = '', requestOptions: RequestOpt throw new Error('invalid host'); } + // 'X-Forwarded-Proto' is the default header const protoHeader: string = process.env.VERDACCIO_FORWARDED_PROTO?.toLocaleLowerCase() ?? HEADERS.FORWARDED_PROTO.toLowerCase(); - const forwardedProtocolHeaderValue = requestOptions.headers[protoHeader] as string | undefined; + const forwardedProtocolHeaderValue = requestOptions.headers[protoHeader]; + + if (Array.isArray(forwardedProtocolHeaderValue)) { + // This really should never happen - only set-cookie is allowed to have + // multiple values. + throw new Error('invalid forwarded protocol header value. Reading header ' + protoHeader); + } const protocol = getWebProtocol(forwardedProtocolHeaderValue, requestOptions.protocol); const combinedUrl = combineBaseUrl(protocol, host, url_prefix); diff --git a/packages/core/url/tests/getPublicUrl.spec.ts b/packages/core/url/tests/getPublicUrl.spec.ts index 0b89df31d..fb7984b07 100644 --- a/packages/core/url/tests/getPublicUrl.spec.ts +++ b/packages/core/url/tests/getPublicUrl.spec.ts @@ -316,6 +316,31 @@ describe('env variable', () => { delete process.env.VERDACCIO_FORWARDED_PROTO; }); + test('with the VERDACCIO_FORWARDED_PROTO environment variable set to "set-cookie"', () => { + process.env.VERDACCIO_FORWARDED_PROTO = 'set-cookie'; + const req = httpMocks.createRequest({ + method: 'GET', + headers: { + host: 'some.com', + cookie: 'name=value; name2=value2;', + 'set-cookie': [ + 'cookieName1=value; expires=Tue, 19 Jan 2038 03:14:07 GMT;', + 'cookieName2=value; expires=Tue, 19 Jan 2038 03:14:07 GMT;', + ], + }, + url: '/', + }); + + expect(() => + getPublicUrl('/test/', { + host: req.hostname, + headers: req.headers as any, + protocol: req.protocol, + }) + ).toThrow('invalid forwarded protocol header value. Reading header set-cookie'); + delete process.env.VERDACCIO_FORWARDED_PROTO; + }); + test('with a invalid X-Forwarded-Proto https and host injection with invalid host', () => { process.env.VERDACCIO_PUBLIC_URL = 'http://injection.test.com">'; const req = httpMocks.createRequest({