VYPR
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.

PackageAffected versionsPatched versions
http-proxy-middlewarenpm
>= 1.3.0, < 2.0.92.0.9
http-proxy-middlewarenpm
>= 3.0.0, < 3.0.53.0.5

Affected products

1

Patches

1
1bdccbeec243

fix(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

News mentions

0

No linked articles in our index yet.