Moderate severityNVD Advisory· Published Apr 15, 2025· Updated Apr 15, 2025
CVE-2025-32997
CVE-2025-32997
Description
In http-proxy-middleware before 2.0.9 and 3.x before 3.0.5, fixRequestBody proceeds even if bodyParser has failed.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
http-proxy-middlewarenpm | >= 1.3.0, < 2.0.9 | 2.0.9 |
http-proxy-middlewarenpm | >= 3.0.0, < 3.0.5 | 3.0.5 |
Affected products
1- Range: 0
Patches
11bdccbeec243fix(fixRequestBody): check readableLength (#1096)
2 files changed · +25 −123
src/handlers/fix-request-body.ts+5 −38 modified@@ -1,26 +1,20 @@ import type * as http from 'http'; import * as querystring from 'querystring'; -import type { Options } from '../types'; -import { getLogger } from '../logger'; - export type BodyParserLikeRequest = http.IncomingMessage & { body?: any }; -type HandleBadRequestArgs = { - proxyReq: http.ClientRequest; - req: BodyParserLikeRequest; - res: http.ServerResponse<http.IncomingMessage>; -}; - /** * Fix proxied body if bodyParser is involved. */ export function fixRequestBody<TReq extends BodyParserLikeRequest = BodyParserLikeRequest>( proxyReq: http.ClientRequest, req: TReq, - res: http.ServerResponse<http.IncomingMessage>, - options: Options, ): void { + // skip fixRequestBody() when req.readableLength not 0 (bodyParser failure) + if (req.readableLength !== 0) { + return; + } + const requestBody = req.body; if (!requestBody) { @@ -33,22 +27,6 @@ export function fixRequestBody<TReq extends BodyParserLikeRequest = BodyParserLi return; } - const logger = getLogger(options); - - // Handle bad request when unexpected "Connect: Upgrade" header is provided - if (/upgrade/gi.test(proxyReq.getHeader('Connection') as string)) { - handleBadRequest({ proxyReq, req, res }); - logger.error(`[HPM] HPM_UNEXPECTED_CONNECTION_UPGRADE_HEADER. Aborted request: ${req.url}`); - return; - } - - // Handle bad request when invalid request body is provided - if (hasInvalidKeys(requestBody)) { - handleBadRequest({ proxyReq, req, res }); - logger.error(`[HPM] HPM_INVALID_REQUEST_DATA. Aborted request: ${req.url}`); - return; - } - const writeBody = (bodyData: string) => { proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData)); proxyReq.write(bodyData); @@ -79,14 +57,3 @@ function handlerFormDataBodyData(contentType: string, data: any) { } return str; } - -function hasInvalidKeys(obj) { - return Object.keys(obj).some((key) => /[\n\r]/.test(key)); -} - -function handleBadRequest({ proxyReq, req, res }: HandleBadRequestArgs) { - res.writeHead(400); - res.end('Bad Request'); - proxyReq.destroy(); - req.destroy(); -}
test/unit/fix-request-body.spec.ts+20 −85 modified@@ -38,7 +38,7 @@ describe('fixRequestBody', () => { jest.spyOn(proxyRequest, 'setHeader'); jest.spyOn(proxyRequest, 'write'); - fixRequestBody(proxyRequest, createRequestWithBody(undefined), fakeProxyResponse(), {}); + fixRequestBody(proxyRequest, createRequestWithBody(undefined)); expect(proxyRequest.setHeader).not.toHaveBeenCalled(); expect(proxyRequest.write).not.toHaveBeenCalled(); @@ -51,7 +51,7 @@ describe('fixRequestBody', () => { jest.spyOn(proxyRequest, 'setHeader'); jest.spyOn(proxyRequest, 'write'); - fixRequestBody(proxyRequest, createRequestWithBody({}), fakeProxyResponse(), {}); + fixRequestBody(proxyRequest, createRequestWithBody({})); expect(proxyRequest.setHeader).toHaveBeenCalled(); expect(proxyRequest.write).toHaveBeenCalled(); @@ -64,12 +64,7 @@ describe('fixRequestBody', () => { jest.spyOn(proxyRequest, 'setHeader'); jest.spyOn(proxyRequest, 'write'); - fixRequestBody( - proxyRequest, - createRequestWithBody({ someField: 'some value' }), - fakeProxyResponse(), - {}, - ); + fixRequestBody(proxyRequest, createRequestWithBody({ someField: 'some value' })); const expectedBody = JSON.stringify({ someField: 'some value' }); expect(proxyRequest.setHeader).toHaveBeenCalledWith('Content-Length', expectedBody.length); @@ -83,12 +78,7 @@ describe('fixRequestBody', () => { jest.spyOn(proxyRequest, 'setHeader'); jest.spyOn(proxyRequest, 'write'); - fixRequestBody( - proxyRequest, - createRequestWithBody({ someField: 'some value' }), - fakeProxyResponse(), - {}, - ); + fixRequestBody(proxyRequest, createRequestWithBody({ someField: 'some value' })); const expectedBody = handlerFormDataBodyData('multipart/form-data', { someField: 'some value', @@ -112,12 +102,7 @@ describe('fixRequestBody', () => { jest.spyOn(proxyRequest, 'setHeader'); jest.spyOn(proxyRequest, 'write'); - fixRequestBody( - proxyRequest, - createRequestWithBody({ someField: 'some value' }), - fakeProxyResponse(), - {}, - ); + fixRequestBody(proxyRequest, createRequestWithBody({ someField: 'some value' })); const expectedBody = handlerFormDataBodyData('multipart/form-data', { someField: 'some value', @@ -142,12 +127,7 @@ describe('fixRequestBody', () => { jest.spyOn(proxyRequest, 'setHeader'); jest.spyOn(proxyRequest, 'write'); - fixRequestBody( - proxyRequest, - createRequestWithBody({ someField: 'some value' }), - fakeProxyResponse(), - {}, - ); + fixRequestBody(proxyRequest, createRequestWithBody({ someField: 'some value' })); const expectedBody = JSON.stringify({ someField: 'some value' }); expect(proxyRequest.setHeader).toHaveBeenCalledWith('Content-Length', expectedBody.length); expect(proxyRequest.write).toHaveBeenCalledWith(expectedBody); @@ -160,12 +140,7 @@ describe('fixRequestBody', () => { jest.spyOn(proxyRequest, 'setHeader'); jest.spyOn(proxyRequest, 'write'); - fixRequestBody( - proxyRequest, - createRequestWithBody({ someField: 'some value' }), - fakeProxyResponse(), - {}, - ); + fixRequestBody(proxyRequest, createRequestWithBody({ someField: 'some value' })); const expectedBody = querystring.stringify({ someField: 'some value' }); expect(proxyRequest.setHeader).toHaveBeenCalledWith('Content-Length', expectedBody.length); @@ -179,12 +154,7 @@ describe('fixRequestBody', () => { jest.spyOn(proxyRequest, 'setHeader'); jest.spyOn(proxyRequest, 'write'); - fixRequestBody( - proxyRequest, - createRequestWithBody({ someField: 'some value' }), - fakeProxyResponse(), - {}, - ); + fixRequestBody(proxyRequest, createRequestWithBody({ someField: 'some value' })); const expectedBody = querystring.stringify({ someField: 'some value' }); expect(proxyRequest.setHeader).toHaveBeenCalledWith('Content-Length', expectedBody.length); @@ -198,69 +168,34 @@ describe('fixRequestBody', () => { jest.spyOn(proxyRequest, 'setHeader'); jest.spyOn(proxyRequest, 'write'); - fixRequestBody( - proxyRequest, - createRequestWithBody({ someField: 'some value' }), - fakeProxyResponse(), - {}, - ); + fixRequestBody(proxyRequest, createRequestWithBody({ someField: 'some value' })); const expectedBody = JSON.stringify({ someField: 'some value' }); expect(proxyRequest.setHeader).toHaveBeenCalledWith('Content-Length', expectedBody.length); expect(proxyRequest.write).toHaveBeenCalledTimes(1); expect(proxyRequest.write).toHaveBeenCalledWith(expectedBody); }); - it('should return 400 and abort request on "Connection: Upgrade" header', () => { + it('should not fixRequestBody() when there bodyParser fails', () => { const proxyRequest = fakeProxyRequest(); - const request = createRequestWithBody({ someField: 'some value' }); - const proxyResponse = fakeProxyResponse(); - proxyRequest.setHeader('connection', 'upgrade'); - proxyRequest.setHeader('content-type', 'application/x-www-form-urlencoded'); - - jest.spyOn(proxyRequest, 'destroy'); - jest.spyOn(request, 'destroy'); - jest.spyOn(proxyResponse, 'writeHead'); - jest.spyOn(proxyResponse, 'end'); - - const logger = { - error: jest.fn(), - }; + const request = { + get readableLength() { + return 4444; // simulate bodyParser failure + }, + } as BodyParserLikeRequest; - fixRequestBody(proxyRequest, request, proxyResponse, { logger }); - - expect(proxyResponse.writeHead).toHaveBeenCalledWith(400); - expect(proxyResponse.end).toHaveBeenCalledTimes(1); - expect(proxyRequest.destroy).toHaveBeenCalledTimes(1); - expect(request.destroy).toHaveBeenCalledTimes(1); - expect(logger.error).toHaveBeenCalledWith( - `[HPM] HPM_UNEXPECTED_CONNECTION_UPGRADE_HEADER. Aborted request: /test_path`, - ); - }); - - it('should return 400 and abort request on invalid request data', () => { - const proxyRequest = fakeProxyRequest(); - const request = createRequestWithBody({ 'INVALID \n\r DATA': '' }); const proxyResponse = fakeProxyResponse(); proxyRequest.setHeader('content-type', 'application/x-www-form-urlencoded'); + jest.spyOn(proxyRequest, 'write'); jest.spyOn(proxyRequest, 'destroy'); - jest.spyOn(request, 'destroy'); jest.spyOn(proxyResponse, 'writeHead'); jest.spyOn(proxyResponse, 'end'); - const logger = { - error: jest.fn(), - }; - - fixRequestBody(proxyRequest, request, proxyResponse, { logger }); + fixRequestBody(proxyRequest, request); - expect(proxyResponse.writeHead).toHaveBeenCalledWith(400); - expect(proxyResponse.end).toHaveBeenCalledTimes(1); - expect(proxyRequest.destroy).toHaveBeenCalledTimes(1); - expect(request.destroy).toHaveBeenCalledTimes(1); - expect(logger.error).toHaveBeenCalledWith( - `[HPM] HPM_INVALID_REQUEST_DATA. Aborted request: /test_path`, - ); + expect(proxyResponse.end).toHaveBeenCalledTimes(0); + expect(proxyRequest.write).toHaveBeenCalledTimes(0); + expect(proxyRequest.destroy).toHaveBeenCalledTimes(0); }); });
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-9gqv-wp59-fq42ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-32997ghsaADVISORY
- github.com/chimurai/http-proxy-middleware/commit/1bdccbeec243850f1d2bb50ea0ff2151e725d67eghsaWEB
- github.com/chimurai/http-proxy-middleware/pull/1096ghsaWEB
- github.com/chimurai/http-proxy-middleware/releases/tag/v2.0.9ghsaWEB
- github.com/chimurai/http-proxy-middleware/releases/tag/v3.0.5ghsaWEB
News mentions
0No linked articles in our index yet.