diff --git a/CHANGELOG.md b/CHANGELOG.md index 92fe7b21..fd3d2727 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## next - fix(types): fix Logger type +- fix(error-response-plugin): sanitize input ## [v3.0.5](https://github.com/chimurai/http-proxy-middleware/releases/tag/v3.0.5) diff --git a/cspell.json b/cspell.json index b257053b..a42ca582 100644 --- a/cspell.json +++ b/cspell.json @@ -19,7 +19,7 @@ "path": "CONTRIBUTORS.txt" } ], - "ignoreRegExpList": ["[a-z]+path", "\\]\\(#[a-z-]+\\)"], + "ignoreRegExpList": ["[a-z]+path", "\\]\\(#[a-z-]+\\)", "%[\\dA-Z]{2}"], "words": [ "brotli", "camelcase", diff --git a/src/plugins/default/error-response-plugin.ts b/src/plugins/default/error-response-plugin.ts index 3af7aca7..edddca83 100644 --- a/src/plugins/default/error-response-plugin.ts +++ b/src/plugins/default/error-response-plugin.ts @@ -3,6 +3,7 @@ import type { Socket } from 'node:net'; import { getStatusCode } from '../../status-code'; import { Plugin } from '../../types'; +import { sanitize } from '../../utils/sanitize'; function isResponseLike(obj: any): obj is http.ServerResponse { return obj && typeof obj.writeHead === 'function'; @@ -26,7 +27,7 @@ export const errorResponsePlugin: Plugin = (proxyServer, options) => { } const host = req.headers && req.headers.host; - res.end(`Error occurred while trying to proxy: ${host}${req.url}`); + res.end(`Error occurred while trying to proxy: ${sanitize(host)}${sanitize(req.url)}`); } else if (isSocketLike(res)) { res.destroy(); } diff --git a/src/utils/sanitize.ts b/src/utils/sanitize.ts new file mode 100644 index 00000000..3a8e5057 --- /dev/null +++ b/src/utils/sanitize.ts @@ -0,0 +1,3 @@ +export function sanitize(input: string | undefined): string { + return input?.replace(/[<>]/g, (i) => encodeURIComponent(i)) ?? ''; +} diff --git a/test/unit/utils/sanitize.spec.ts b/test/unit/utils/sanitize.spec.ts new file mode 100644 index 00000000..ee43da25 --- /dev/null +++ b/test/unit/utils/sanitize.spec.ts @@ -0,0 +1,17 @@ +import { sanitize } from '../../../src/utils/sanitize'; + +describe('sanitize()', () => { + it('should return empty string for undefined input', () => { + expect(sanitize(undefined)).toEqual(''); + }); + + it('should replace special characters with their HTML entity equivalents', () => { + const input = '<>'; + expect(sanitize(input)).toMatchInlineSnapshot(`"%3C%3E"`); + }); + + it('should replace special characters with HTML entities', () => { + const input = ''; + expect(sanitize(input)).toMatchInlineSnapshot(`"%3Cscript%3Ealert("XSS")%3C/script%3E"`); + }); +});