Security context
MediumGHSA-ggv3-7p47-pfv8 CVE-2026-29057CWE-444Published Mar 17, 2026

Next.js: HTTP request smuggling in rewrites

Research this vulnerability

Research is free — Hunters explains how the bug works, the root-cause code pattern, how the fix addresses it, and how to test whether a target is affected, in chat. Investigate & write exploit is a paid run — the engine reads the advisory and fix commits, then builds and validates a working proof-of-concept exploit with reproduction steps.

Affected versions

16.0.0-beta.0 → fixed in 16.1.79.5.0 → fixed in 15.5.13

Details

## Summary When Next.js rewrites proxy traffic to an external backend, a crafted `DELETE`/`OPTIONS` request using `Transfer-Encoding: chunked` could trigger request boundary disagreement between the proxy and backend. This could allow request smuggling through rewritten routes. ## Impact An attacker could smuggle a second request to unintended backend routes (for example, internal/admin endpoints), bypassing assumptions that only the configured rewrite destination/path is reachable. This does not impact applications hosted on providers that handle rewrites at the CDN level, such as Vercel. ## Patches The vulnerability originated in an upstream library vendored by Next.js. It is fixed by updating that dependency’s behavior so `content-length: 0` is added only when both `content-length` and `transfer-encoding` are absent, and `transfer-encoding` is no longer removed in that code path. ## Workarounds If upgrade is not immediately possible: - Block chunked `DELETE`/`OPTIONS` requests on rewritten routes at your edge/proxy. - Enforce authentication/authorization on backend routes per our [security guidance](https://nextjs.org/docs/app/guides/data-security).

The fix

[backport]: fix: patch http-proxy to prevent request

Zack Tanner· Mar 5, 2026, 03:52 PM+3509dc98c04f37
package.json+1 0
@@ -338,6 +338,7 @@
"webpack-sources@3.2.3": "patches/webpack-sources@3.2.3.patch",
"stacktrace-parser@0.1.10": "patches/stacktrace-parser@0.1.10.patch",
"@types/node@20.17.6": "patches/@types__node@20.17.6.patch",
+ "http-proxy@1.18.1": "patches/http-proxy@1.18.1.patch",
"taskr@1.1.0": "patches/taskr@1.1.0.patch"
}
}
packages/next/src/compiled/http-proxy/index.js+5 5
@@ -1,4 +1,4 @@
-(()=>{var e={993:e=>{"use strict";var t=Object.prototype.hasOwnProperty,r="~";function Events(){}if(Object.create){Events.prototype=Object.create(null);if(!(new Events).__proto__)r=false}function EE(e,t,r){this.fn=e;this.context=t;this.once=r||false}function addListener(e,t,o,s,n){if(typeof o!=="function"){throw new TypeError("The listener must be a function")}var i=new EE(o,s||e,n),a=r?r+t:t;if(!e._events[a])e._events[a]=i,e._eventsCount++;else if(!e._events[a].fn)e._events[a].push(i);else e._events[a]=[e._events[a],i];return e}function clearEvent(e,t){if(--e._eventsCount===0)e._events=new Events;else delete e._events[t]}function EventEmitter(){this._events=new Events;this._eventsCount=0}EventEmitter.prototype.eventNames=function eventNames(){var e=[],o,s;if(this._eventsCount===0)return e;for(s in o=this._events){if(t.call(o,s))e.push(r?s.slice(1):s)}if(Object.getOwnPropertySymbols){return e.concat(Object.getOwnPropertySymbols(o))}return e};EventEmitter.prototype.listeners=function listeners(e){var t=r?r+e:e,o=this._events[t];if(!o)return[];if(o.fn)return[o.fn];for(var s=0,n=o.length,i=new Array(n);s<n;s++){i[s]=o[s].fn}return i};EventEmitter.prototype.listenerCount=function listenerCount(e){var t=r?r+e:e,o=this._events[t];if(!o)return 0;if(o.fn)return 1;return o.length};EventEmitter.prototype.emit=function emit(e,t,o,s,n,i){var a=r?r+e:e;if(!this._events[a])return false;var c=this._events[a],u=arguments.length,f,h;if(c.fn){if(c.once)this.removeListener(e,c.fn,undefined,true);switch(u){case 1:return c.fn.call(c.context),true;case 2:return c.fn.call(c.context,t),true;case 3:return c.fn.call(c.context,t,o),true;case 4:return c.fn.call(c.context,t,o,s),true;case 5:return c.fn.call(c.context,t,o,s,n),true;case 6:return c.fn.call(c.context,t,o,s,n,i),true}for(h=1,f=new Array(u-1);h<u;h++){f[h-1]=arguments[h]}c.fn.apply(c.context,f)}else{var p=c.length,d;for(h=0;h<p;h++){if(c[h].once)this.removeListener(e,c[h].fn,undefined,true);switch(u){case 1:c[h].fn.call(c[h].context);break;case 2:c[h].fn.call(c[h].context,t);break;case 3:c[h].fn.call(c[h].context,t,o);break;case 4:c[h].fn.call(c[h].context,t,o,s);break;default:if(!f)for(d=1,f=new Array(u-1);d<u;d++){f[d-1]=arguments[d]}c[h].fn.apply(c[h].context,f)}}}return true};EventEmitter.prototype.on=function on(e,t,r){return addListener(this,e,t,r,false)};EventEmitter.prototype.once=function once(e,t,r){return addListener(this,e,t,r,true)};EventEmitter.prototype.removeListener=function removeListener(e,t,o,s){var n=r?r+e:e;if(!this._events[n])return this;if(!t){clearEvent(this,n);return this}var i=this._events[n];if(i.fn){if(i.fn===t&&(!s||i.once)&&(!o||i.context===o)){clearEvent(this,n)}}else{for(var a=0,c=[],u=i.length;a<u;a++){if(i[a].fn!==t||s&&!i[a].once||o&&i[a].context!==o){c.push(i[a])}}if(c.length)this._events[n]=c.length===1?c[0]:c;else clearEvent(this,n)}return this};EventEmitter.prototype.removeAllListeners=function removeAllListeners(e){var t;if(e){t=r?r+e:e;if(this._events[t])clearEvent(this,t)}else{this._events=new Events;this._eventsCount=0}return this};EventEmitter.prototype.off=EventEmitter.prototype.removeListener;EventEmitter.prototype.addListener=EventEmitter.prototype.on;EventEmitter.prefixed=r;EventEmitter.EventEmitter=EventEmitter;if(true){e.exports=EventEmitter}},900:(e,t,r)=>{var o=r(310);var s=o.URL;var n=r(685);var i=r(687);var a=r(491);var c=r(781).Writable;var u=r(937)("follow-redirects");var f={GET:true,HEAD:true,OPTIONS:true,TRACE:true};var h=Object.create(null);["abort","aborted","connect","error","socket","timeout"].forEach((function(e){h[e]=function(t,r,o){this._redirectable.emit(e,t,r,o)}}));function RedirectableRequest(e,t){c.call(this);this._sanitizeOptions(e);this._options=e;this._ended=false;this._ending=false;this._redirectCount=0;this._redirects=[];this._requestBodyLength=0;this._requestBodyBuffers=[];if(t){this.on("response",t)}var r=this;this._onNativeResponse=function(e){r._processResponse(e)};this._performRequest()}RedirectableRequest.prototype=Object.create(c.prototype);RedirectableRequest.prototype.write=function(e,t,r){if(this._ending){throw new Error("write after end")}if(!(typeof e==="string"||typeof e==="object"&&"length"in e)){throw new Error("data should be a string, Buffer or Uint8Array")}if(typeof t==="function"){r=t;t=null}if(e.length===0){if(r){r()}return}if(this._requestBodyLength+e.length<=this._options.maxBodyLength){this._requestBodyLength+=e.length;this._requestBodyBuffers.push({data:e,encoding:t});this._currentRequest.write(e,t,r)}else{this.emit("error",new Error("Request body larger than maxBodyLength limit"));this.abort()}};RedirectableRequest.prototype.end=function(e,t,r){if(typeof e==="function"){r=e;e=t=null}else if(typeof t==="function"){r=t;t=null}if(!e){this._ended=this._ending=true;this._currentRequest.end(null,null,r)}else{var o=this;var s=this._currentRequest;this.write(e,t,(function(){o._ended=true;s.end(null,null,r)}));this._ending=true}};RedirectableRequest.prototype.setHeader=function(e,t){this._options.headers[e]=t;this._currentRequest.setHeader(e,t)};RedirectableRequest.prototype.removeHeader=function(e){delete this._options.headers[e];this._currentRequest.removeHeader(e)};RedirectableRequest.prototype.setTimeout=function(e,t){if(t){this.once("timeout",t)}if(this.socket){startTimer(this,e)}else{var r=this;this._currentRequest.once("socket",(function(){startTimer(r,e)}))}this.once("response",clearTimer);this.once("error",clearTimer);return this};function startTimer(e,t){clearTimeout(e._timeout);e._timeout=setTimeout((function(){e.emit("timeout")}),t)}function clearTimer(){clearTimeout(this._timeout)}["abort","flushHeaders","getHeader","setNoDelay","setSocketKeepAlive"].forEach((function(e){RedirectableRequest.prototype[e]=function(t,r){return this._currentRequest[e](t,r)}}));["aborted","connection","socket"].forEach((function(e){Object.defineProperty(RedirectableRequest.prototype,e,{get:function(){return this._currentRequest[e]}})}));RedirectableRequest.prototype._sanitizeOptions=function(e){if(!e.headers){e.headers={}}if(e.host){if(!e.hostname){e.hostname=e.host}delete e.host}if(!e.pathname&&e.path){var t=e.path.indexOf("?");if(t<0){e.pathname=e.path}else{e.pathname=e.path.substring(0,t);e.search=e.path.substring(t)}}};RedirectableRequest.prototype._performRequest=function(){var e=this._options.protocol;var t=this._options.nativeProtocols[e];if(!t){this.emit("error",new Error("Unsupported protocol "+e));return}if(this._options.agents){var r=e.substr(0,e.length-1);this._options.agent=this._options.agents[r]}var s=this._currentRequest=t.request(this._options,this._onNativeResponse);this._currentUrl=o.format(this._options);s._redirectable=this;for(var n in h){if(n){s.on(n,h[n])}}if(this._isRedirect){var i=0;var a=this;var c=this._requestBodyBuffers;(function writeNext(e){if(s===a._currentRequest){if(e){a.emit("error",e)}else if(i<c.length){var t=c[i++];if(!s.finished){s.write(t.data,t.encoding,writeNext)}}else if(a._ended){s.end()}}})()}};RedirectableRequest.prototype._processResponse=function(e){var t=e.statusCode;if(this._options.trackRedirects){this._redirects.push({url:this._currentUrl,headers:e.headers,statusCode:t})}var r=e.headers.location;if(r&&this._options.followRedirects!==false&&t>=300&&t<400){this._currentRequest.removeAllListeners();this._currentRequest.on("error",noop);this._currentRequest.abort();e.destroy();if(++this._redirectCount>this._options.maxRedirects){this.emit("error",new Error("Max redirects exceeded."));return}var s;var n=this._options.headers;if(t!==307&&!(this._options.method in f)){this._options.method="GET";this._requestBodyBuffers=[];for(s in n){if(/^content-/i.test(s)){delete n[s]}}}if(!this._isRedirect){for(s in n){if(/^host$/i.test(s)){delete n[s]}}}var i=o.resolve(this._currentUrl,r);u("redirecting to",i);Object.assign(this._options,o.parse(i));if(typeof this._options.beforeRedirect==="function"){try{this._options.beforeRedirect.call(null,this._options)}catch(e){this.emit("error",e);return}this._sanitizeOptions(this._options)}this._isRedirect=true;this._performRequest()}else{e.responseUrl=this._currentUrl;e.redirects=this._redirects;this.emit("response",e);this._requestBodyBuffers=[]}};function wrap(e){var t={maxRedirects:21,maxBodyLength:10*1024*1024};var r={};Object.keys(e).forEach((function(n){var i=n+":";var c=r[i]=e[n];var f=t[n]=Object.create(c);f.request=function(e,n,c){if(typeof e==="string"){var f=e;try{e=urlToOptions(new s(f))}catch(t){e=o.parse(f)}}else if(s&&e instanceof s){e=urlToOptions(e)}else{c=n;n=e;e={protocol:i}}if(typeof n==="function"){c=n;n=null}n=Object.assign({maxRedirects:t.maxRedirects,maxBodyLength:t.maxBodyLength},e,n);n.nativeProtocols=r;a.equal(n.protocol,i,"protocol mismatch");u("options",n);return new RedirectableRequest(n,c)};f.get=function(e,t,r){var o=f.request(e,t,r);o.end();return o}}));return t}function noop(){}function urlToOptions(e){var t={protocol:e.protocol,hostname:e.hostname.startsWith("[")?e.hostname.slice(1,-1):e.hostname,hash:e.hash,search:e.search,pathname:e.pathname,path:e.pathname+e.search,href:e.href};if(e.port!==""){t.port=Number(e.port)}return t}e.exports=wrap({http:n,https:i});e.exports.wrap=wrap},413:(e,t,r)=>{
+(()=>{var e={993:e=>{"use strict";var t=Object.prototype.hasOwnProperty,r="~";function Events(){}if(Object.create){Events.prototype=Object.create(null);if(!(new Events).__proto__)r=false}function EE(e,t,r){this.fn=e;this.context=t;this.once=r||false}function addListener(e,t,o,n,s){if(typeof o!=="function"){throw new TypeError("The listener must be a function")}var i=new EE(o,n||e,s),a=r?r+t:t;if(!e._events[a])e._events[a]=i,e._eventsCount++;else if(!e._events[a].fn)e._events[a].push(i);else e._events[a]=[e._events[a],i];return e}function clearEvent(e,t){if(--e._eventsCount===0)e._events=new Events;else delete e._events[t]}function EventEmitter(){this._events=new Events;this._eventsCount=0}EventEmitter.prototype.eventNames=function eventNames(){var e=[],o,n;if(this._eventsCount===0)return e;for(n in o=this._events){if(t.call(o,n))e.push(r?n.slice(1):n)}if(Object.getOwnPropertySymbols){return e.concat(Object.getOwnPropertySymbols(o))}return e};EventEmitter.prototype.listeners=function listeners(e){var t=r?r+e:e,o=this._events[t];if(!o)return[];if(o.fn)return[o.fn];for(var n=0,s=o.length,i=new Array(s);n<s;n++){i[n]=o[n].fn}return i};EventEmitter.prototype.listenerCount=function listenerCount(e){var t=r?r+e:e,o=this._events[t];if(!o)return 0;if(o.fn)return 1;return o.length};EventEmitter.prototype.emit=function emit(e,t,o,n,s,i){var a=r?r+e:e;if(!this._events[a])return false;var c=this._events[a],u=arguments.length,f,h;if(c.fn){if(c.once)this.removeListener(e,c.fn,undefined,true);switch(u){case 1:return c.fn.call(c.context),true;case 2:return c.fn.call(c.context,t),true;case 3:return c.fn.call(c.context,t,o),true;case 4:return c.fn.call(c.context,t,o,n),true;case 5:return c.fn.call(c.context,t,o,n,s),true;case 6:return c.fn.call(c.context,t,o,n,s,i),true}for(h=1,f=new Array(u-1);h<u;h++){f[h-1]=arguments[h]}c.fn.apply(c.context,f)}else{var p=c.length,d;for(h=0;h<p;h++){if(c[h].once)this.removeListener(e,c[h].fn,undefined,true);switch(u){case 1:c[h].fn.call(c[h].context);break;case 2:c[h].fn.call(c[h].context,t);break;case 3:c[h].fn.call(c[h].context,t,o);break;case 4:c[h].fn.call(c[h].context,t,o,n);break;default:if(!f)for(d=1,f=new Array(u-1);d<u;d++){f[d-1]=arguments[d]}c[h].fn.apply(c[h].context,f)}}}return true};EventEmitter.prototype.on=function on(e,t,r){return addListener(this,e,t,r,false)};EventEmitter.prototype.once=function once(e,t,r){return addListener(this,e,t,r,true)};EventEmitter.prototype.removeListener=function removeListener(e,t,o,n){var s=r?r+e:e;if(!this._events[s])return this;if(!t){clearEvent(this,s);return this}var i=this._events[s];if(i.fn){if(i.fn===t&&(!n||i.once)&&(!o||i.context===o)){clearEvent(this,s)}}else{for(var a=0,c=[],u=i.length;a<u;a++){if(i[a].fn!==t||n&&!i[a].once||o&&i[a].context!==o){c.push(i[a])}}if(c.length)this._events[s]=c.length===1?c[0]:c;else clearEvent(this,s)}return this};EventEmitter.prototype.removeAllListeners=function removeAllListeners(e){var t;if(e){t=r?r+e:e;if(this._events[t])clearEvent(this,t)}else{this._events=new Events;this._eventsCount=0}return this};EventEmitter.prototype.off=EventEmitter.prototype.removeListener;EventEmitter.prototype.addListener=EventEmitter.prototype.on;EventEmitter.prefixed=r;EventEmitter.EventEmitter=EventEmitter;if(true){e.exports=EventEmitter}},900:(e,t,r)=>{var o=r(310);var n=o.URL;var s=r(685);var i=r(687);var a=r(491);var c=r(781).Writable;var u=r(937)("follow-redirects");var f={GET:true,HEAD:true,OPTIONS:true,TRACE:true};var h=Object.create(null);["abort","aborted","connect","error","socket","timeout"].forEach((function(e){h[e]=function(t,r,o){this._redirectable.emit(e,t,r,o)}}));function RedirectableRequest(e,t){c.call(this);this._sanitizeOptions(e);this._options=e;this._ended=false;this._ending=false;this._redirectCount=0;this._redirects=[];this._requestBodyLength=0;this._requestBodyBuffers=[];if(t){this.on("response",t)}var r=this;this._onNativeResponse=function(e){r._processResponse(e)};this._performRequest()}RedirectableRequest.prototype=Object.create(c.prototype);RedirectableRequest.prototype.write=function(e,t,r){if(this._ending){throw new Error("write after end")}if(!(typeof e==="string"||typeof e==="object"&&"length"in e)){throw new Error("data should be a string, Buffer or Uint8Array")}if(typeof t==="function"){r=t;t=null}if(e.length===0){if(r){r()}return}if(this._requestBodyLength+e.length<=this._options.maxBodyLength){this._requestBodyLength+=e.length;this._requestBodyBuffers.push({data:e,encoding:t});this._currentRequest.write(e,t,r)}else{this.emit("error",new Error("Request body larger than maxBodyLength limit"));this.abort()}};RedirectableRequest.prototype.end=function(e,t,r){if(typeof e==="function"){r=e;e=t=null}else if(typeof t==="function"){r=t;t=null}if(!e){this._ended=this._ending=true;this._currentRequest.end(null,null,r)}else{var o=this;var n=this._currentRequest;this.write(e,t,(function(){o._ended=true;n.end(null,null,r)}));this._ending=true}};RedirectableRequest.prototype.setHeader=function(e,t){this._options.headers[e]=t;this._currentRequest.setHeader(e,t)};RedirectableRequest.prototype.removeHeader=function(e){delete this._options.headers[e];this._currentRequest.removeHeader(e)};RedirectableRequest.prototype.setTimeout=function(e,t){if(t){this.once("timeout",t)}if(this.socket){startTimer(this,e)}else{var r=this;this._currentRequest.once("socket",(function(){startTimer(r,e)}))}this.once("response",clearTimer);this.once("error",clearTimer);return this};function startTimer(e,t){clearTimeout(e._timeout);e._timeout=setTimeout((function(){e.emit("timeout")}),t)}function clearTimer(){clearTimeout(this._timeout)}["abort","flushHeaders","getHeader","setNoDelay","setSocketKeepAlive"].forEach((function(e){RedirectableRequest.prototype[e]=function(t,r){return this._currentRequest[e](t,r)}}));["aborted","connection","socket"].forEach((function(e){Object.defineProperty(RedirectableRequest.prototype,e,{get:function(){return this._currentRequest[e]}})}));RedirectableRequest.prototype._sanitizeOptions=function(e){if(!e.headers){e.headers={}}if(e.host){if(!e.hostname){e.hostname=e.host}delete e.host}if(!e.pathname&&e.path){var t=e.path.indexOf("?");if(t<0){e.pathname=e.path}else{e.pathname=e.path.substring(0,t);e.search=e.path.substring(t)}}};RedirectableRequest.prototype._performRequest=function(){var e=this._options.protocol;var t=this._options.nativeProtocols[e];if(!t){this.emit("error",new Error("Unsupported protocol "+e));return}if(this._options.agents){var r=e.substr(0,e.length-1);this._options.agent=this._options.agents[r]}var n=this._currentRequest=t.request(this._options,this._onNativeResponse);this._currentUrl=o.format(this._options);n._redirectable=this;for(var s in h){if(s){n.on(s,h[s])}}if(this._isRedirect){var i=0;var a=this;var c=this._requestBodyBuffers;(function writeNext(e){if(n===a._currentRequest){if(e){a.emit("error",e)}else if(i<c.length){var t=c[i++];if(!n.finished){n.write(t.data,t.encoding,writeNext)}}else if(a._ended){n.end()}}})()}};RedirectableRequest.prototype._processResponse=function(e){var t=e.statusCode;if(this._options.trackRedirects){this._redirects.push({url:this._currentUrl,headers:e.headers,statusCode:t})}var r=e.headers.location;if(r&&this._options.followRedirects!==false&&t>=300&&t<400){this._currentRequest.removeAllListeners();this._currentRequest.on("error",noop);this._currentRequest.abort();e.destroy();if(++this._redirectCount>this._options.maxRedirects){this.emit("error",new Error("Max redirects exceeded."));return}var n;var s=this._options.headers;if(t!==307&&!(this._options.method in f)){this._options.method="GET";this._requestBodyBuffers=[];for(n in s){if(/^content-/i.test(n)){delete s[n]}}}if(!this._isRedirect){for(n in s){if(/^host$/i.test(n)){delete s[n]}}}var i=o.resolve(this._currentUrl,r);u("redirecting to",i);Object.assign(this._options,o.parse(i));if(typeof this._options.beforeRedirect==="function"){try{this._options.beforeRedirect.call(null,this._options)}catch(e){this.emit("error",e);return}this._sanitizeOptions(this._options)}this._isRedirect=true;this._performRequest()}else{e.responseUrl=this._currentUrl;e.redirects=this._redirects;this.emit("response",e);this._requestBodyBuffers=[]}};function wrap(e){var t={maxRedirects:21,maxBodyLength:10*1024*1024};var r={};Object.keys(e).forEach((function(s){var i=s+":";var c=r[i]=e[s];var f=t[s]=Object.create(c);f.request=function(e,s,c){if(typeof e==="string"){var f=e;try{e=urlToOptions(new n(f))}catch(t){e=o.parse(f)}}else if(n&&e instanceof n){e=urlToOptions(e)}else{c=s;s=e;e={protocol:i}}if(typeof s==="function"){c=s;s=null}s=Object.assign({maxRedirects:t.maxRedirects,maxBodyLength:t.maxBodyLength},e,s);s.nativeProtocols=r;a.equal(s.protocol,i,"protocol mismatch");u("options",s);return new RedirectableRequest(s,c)};f.get=function(e,t,r){var o=f.request(e,t,r);o.end();return o}}));return t}function noop(){}function urlToOptions(e){var t={protocol:e.protocol,hostname:e.hostname.startsWith("[")?e.hostname.slice(1,-1):e.hostname,hash:e.hash,search:e.search,pathname:e.pathname,path:e.pathname+e.search,href:e.href};if(e.port!==""){t.port=Number(e.port)}return t}e.exports=wrap({http:s,https:i});e.exports.wrap=wrap},204:(e,t,r)=>{
/*!
* Caron dimonio, con occhi di bragia
* loro accennando, tutte le raccoglie;
@@ -10,25 +10,25 @@
*
* Dante - The Divine Comedy (Canto III)
*/
-e.exports=r(82)},82:(e,t,r)=>{var o=r(846).Server;function createProxyServer(e){return new o(e)}o.createProxyServer=createProxyServer;o.createServer=createProxyServer;o.createProxy=createProxyServer;e.exports=o},29:(e,t,r)=>{var o=t,s=r(310),n=r(837)._extend,i=r(85);var a=/(^|,)\s*upgrade\s*($|,)/i,c=/^https|wss/;o.isSSL=c;o.setupOutgoing=function(e,t,r,u){e.port=t[u||"target"].port||(c.test(t[u||"target"].protocol)?443:80);["host","hostname","socketPath","pfx","key","passphrase","cert","ca","ciphers","secureProtocol"].forEach((function(r){e[r]=t[u||"target"][r]}));e.method=t.method||r.method;e.headers=n({},r.headers);if(t.headers){n(e.headers,t.headers)}if(t.auth){e.auth=t.auth}if(t.ca){e.ca=t.ca}if(c.test(t[u||"target"].protocol)){e.rejectUnauthorized=typeof t.secure==="undefined"?true:t.secure}e.agent=t.agent||false;e.localAddress=t.localAddress;if(!e.agent){e.headers=e.headers||{};if(typeof e.headers.connection!=="string"||!a.test(e.headers.connection)){e.headers.connection="close"}}var f=t[u||"target"];var h=f&&t.prependPath!==false?f.path||"":"";var p=!t.toProxy?s.parse(r.url).path||"":r.url;p=!t.ignorePath?p:"";e.path=o.urlJoin(h,p);if(t.changeOrigin){e.headers.host=i(e.port,t[u||"target"].protocol)&&!hasPort(e.host)?e.host+":"+e.port:e.host}return e};o.setupSocket=function(e){e.setTimeout(0);e.setNoDelay(true);e.setKeepAlive(true,0);return e};o.getPort=function(e){var t=e.headers.host?e.headers.host.match(/:(\d+)/):"";return t?t[1]:o.hasEncryptedConnection(e)?"443":"80"};o.hasEncryptedConnection=function(e){return Boolean(e.connection.encrypted||e.connection.pair)};o.urlJoin=function(){var e=Array.prototype.slice.call(arguments),t=e.length-1,r=e[t],o=r.split("?"),s;e[t]=o.shift();s=[e.filter(Boolean).join("/").replace(/\/+/g,"/").replace("http:/","http://").replace("https:/","https://")];s.push.apply(s,o);return s.join("?")};o.rewriteCookieProperty=function rewriteCookieProperty(e,t,r){if(Array.isArray(e)){return e.map((function(e){return rewriteCookieProperty(e,t,r)}))}return e.replace(new RegExp("(;\\s*"+r+"=)([^;]+)","i"),(function(e,r,o){var s;if(o in t){s=t[o]}else if("*"in t){s=t["*"]}else{return e}if(s){return r+s}else{return""}}))};function hasPort(e){return!!~e.indexOf(":")}},846:(e,t,r)=>{var o=e.exports,s=r(837)._extend,n=r(310).parse,i=r(993),a=r(685),c=r(687),u=r(249),f=r(558);o.Server=ProxyServer;function createRightProxy(e){return function(t){return function(r,o){var i=e==="ws"?this.wsPasses:this.webPasses,a=[].slice.call(arguments),c=a.length-1,u,f;if(typeof a[c]==="function"){f=a[c];c--}var h=t;if(!(a[c]instanceof Buffer)&&a[c]!==o){h=s({},t);s(h,a[c]);c--}if(a[c]instanceof Buffer){u=a[c]}["target","forward"].forEach((function(e){if(typeof h[e]==="string")h[e]=n(h[e])}));if(!h.target&&!h.forward){return this.emit("error",new Error("Must provide a proper URL as target"))}for(var p=0;p<i.length;p++){if(i[p](r,o,h,u,this,f)){break}}}}}o.createRightProxy=createRightProxy;function ProxyServer(e){i.call(this);e=e||{};e.prependPath=e.prependPath===false?false:true;this.web=this.proxyRequest=createRightProxy("web")(e);this.ws=this.proxyWebsocketRequest=createRightProxy("ws")(e);this.options=e;this.webPasses=Object.keys(u).map((function(e){return u[e]}));this.wsPasses=Object.keys(f).map((function(e){return f[e]}));this.on("error",this.onError,this)}r(837).inherits(ProxyServer,i);ProxyServer.prototype.onError=function(e){if(this.listeners("error").length===1){throw e}};ProxyServer.prototype.listen=function(e,t){var r=this,closure=function(e,t){r.web(e,t)};this._server=this.options.ssl?c.createServer(this.options.ssl,closure):a.createServer(closure);if(this.options.ws){this._server.on("upgrade",(function(e,t,o){r.ws(e,t,o)}))}this._server.listen(e,t);return this};ProxyServer.prototype.close=function(e){var t=this;if(this._server){this._server.close(done)}function done(){t._server=null;if(e){e.apply(null,arguments)}}};ProxyServer.prototype.before=function(e,t,r){if(e!=="ws"&&e!=="web"){throw new Error("type must be `web` or `ws`")}var o=e==="ws"?this.wsPasses:this.webPasses,s=false;o.forEach((function(e,r){if(e.name===t)s=r}));if(s===false)throw new Error("No such pass");o.splice(s,0,r)};ProxyServer.prototype.after=function(e,t,r){if(e!=="ws"&&e!=="web"){throw new Error("type must be `web` or `ws`")}var o=e==="ws"?this.wsPasses:this.webPasses,s=false;o.forEach((function(e,r){if(e.name===t)s=r}));if(s===false)throw new Error("No such pass");o.splice(s++,0,r)}},249:(e,t,r)=>{var o=r(685),s=r(687),n=r(470),i=r(29),a=r(900);n=Object.keys(n).map((function(e){return n[e]}));var c={http:o,https:s};
+e.exports=r(763)},763:(e,t,r)=>{var o=r(458).Server;function createProxyServer(e){return new o(e)}o.createProxyServer=createProxyServer;o.createServer=createProxyServer;o.createProxy=createProxyServer;e.exports=o},341:(e,t,r)=>{var o=t,n=r(310),s=r(85);var i=/(^|,)\s*upgrade\s*($|,)/i,a=/(^|,)\s*transfer-encoding\s*($|,)/i,c=/^https|wss/;o.isSSL=c;o.setupOutgoing=function(e,t,r,u){e.port=t[u||"target"].port||(c.test(t[u||"target"].protocol)?443:80);["host","hostname","socketPath","pfx","key","passphrase","cert","ca","ciphers","secureProtocol"].forEach((function(r){e[r]=t[u||"target"][r]}));e.method=t.method||r.method;e.headers=Object.assign({},r.headers);if(t.headers){Object.assign(e.headers,t.headers)}if(t.auth){e.auth=t.auth}if(t.ca){e.ca=t.ca}if(c.test(t[u||"target"].protocol)){e.rejectUnauthorized=typeof t.secure==="undefined"?true:t.secure}e.agent=t.agent||false;e.localAddress=t.localAddress;e.headers=e.headers||{};var f=Object.keys(e.headers).some((function(t){return t.toLowerCase()==="transfer-encoding"&&typeof e.headers[t]!=="undefined"}));if(f||typeof e.headers.connection==="string"&&a.test(e.headers.connection)){e.headers.connection="close"}if(!e.agent){if(typeof e.headers.connection!=="string"||!i.test(e.headers.connection)){e.headers.connection="close"}}var h=t[u||"target"];var p=h&&t.prependPath!==false?h.path||"":"";var d=!t.toProxy?n.parse(r.url).path||"":r.url;d=!t.ignorePath?d:"";e.path=o.urlJoin(p,d);if(t.changeOrigin){e.headers.host=s(e.port,t[u||"target"].protocol)&&!hasPort(e.host)?e.host+":"+e.port:e.host}return e};o.setupSocket=function(e){e.setTimeout(0);e.setNoDelay(true);e.setKeepAlive(true,0);return e};o.getPort=function(e){var t=e.headers.host?e.headers.host.match(/:(\d+)/):"";return t?t[1]:o.hasEncryptedConnection(e)?"443":"80"};o.hasEncryptedConnection=function(e){return Boolean(e.connection.encrypted||e.connection.pair)};o.urlJoin=function(){var e=Array.prototype.slice.call(arguments),t=e.length-1,r=e[t],o=r.split("?"),n;e[t]=o.shift();n=[e.filter(Boolean).join("/").replace(/\/+/g,"/").replace("http:/","http://").replace("https:/","https://")];n.push.apply(n,o);return n.join("?")};o.rewriteCookieProperty=function rewriteCookieProperty(e,t,r){if(Array.isArray(e)){return e.map((function(e){return rewriteCookieProperty(e,t,r)}))}return e.replace(new RegExp("(;\\s*"+r+"=)([^;]+)","i"),(function(e,r,o){var n;if(o in t){n=t[o]}else if("*"in t){n=t["*"]}else{return e}if(n){return r+n}else{return""}}))};function hasPort(e){return!!~e.indexOf(":")}},458:(e,t,r)=>{var o=e.exports,n=r(310).parse,s=r(993),i=r(685),a=r(687),c=r(101),u=r(761);o.Server=ProxyServer;function createRightProxy(e){return function(t){return function(r,o){var s=e==="ws"?this.wsPasses:this.webPasses,i=[].slice.call(arguments),a=i.length-1,c,u;if(typeof i[a]==="function"){u=i[a];a--}var f=t;if(!(i[a]instanceof Buffer)&&i[a]!==o){f=Object.assign({},t);Object.assign(f,i[a]);a--}if(i[a]instanceof Buffer){c=i[a]}["target","forward"].forEach((function(e){if(typeof f[e]==="string")f[e]=n(f[e])}));if(!f.target&&!f.forward){return this.emit("error",new Error("Must provide a proper URL as target"))}for(var h=0;h<s.length;h++){if(s[h](r,o,f,c,this,u)){break}}}}}o.createRightProxy=createRightProxy;function ProxyServer(e){s.call(this);e=e||{};e.prependPath=e.prependPath===false?false:true;this.web=this.proxyRequest=createRightProxy("web")(e);this.ws=this.proxyWebsocketRequest=createRightProxy("ws")(e);this.options=e;this.webPasses=Object.keys(c).map((function(e){return c[e]}));this.wsPasses=Object.keys(u).map((function(e){return u[e]}));this.on("error",this.onError,this)}r(837).inherits(ProxyServer,s);ProxyServer.prototype.onError=function(e){if(this.listeners("error").length===1){throw e}};ProxyServer.prototype.listen=function(e,t){var r=this,closure=function(e,t){r.web(e,t)};this._server=this.options.ssl?a.createServer(this.options.ssl,closure):i.createServer(closure);if(this.options.ws){this._server.on("upgrade",(function(e,t,o){r.ws(e,t,o)}))}this._server.listen(e,t);return this};ProxyServer.prototype.close=function(e){var t=this;if(this._server){this._server.close(done)}function done(){t._server=null;if(e){e.apply(null,arguments)}}};ProxyServer.prototype.before=function(e,t,r){if(e!=="ws"&&e!=="web"){throw new Error("type must be `web` or `ws`")}var o=e==="ws"?this.wsPasses:this.webPasses,n=false;o.forEach((function(e,r){if(e.name===t)n=r}));if(n===false)throw new Error("No such pass");o.splice(n,0,r)};ProxyServer.prototype.after=function(e,t,r){if(e!=="ws"&&e!=="web"){throw new Error("type must be `web` or `ws`")}var o=e==="ws"?this.wsPasses:this.webPasses,n=false;o.forEach((function(e,r){if(e.name===t)n=r}));if(n===false)throw new Error("No such pass");o.splice(n++,0,r)}},101:(e,t,r)=>{var o=r(685),n=r(687),s=r(445),i=r(341),a=r(900);s=Object.keys(s).map((function(e){return s[e]}));var c={http:o,https:n};
/*!
* Array of passes.
*
* A `pass` is just a function that is executed on `req, res, options`
* so that you can easily add new checks while still keeping the base
* flexible.
- */e.exports={deleteLength:function deleteLength(e,t,r){if((e.method==="DELETE"||e.method==="OPTIONS")&&!e.headers["content-length"]){e.headers["content-length"]="0";delete e.headers["transfer-encoding"]}},timeout:function timeout(e,t,r){if(r.timeout){e.socket.setTimeout(r.timeout)}},XHeaders:function XHeaders(e,t,r){if(!r.xfwd)return;var o=e.isSpdy||i.hasEncryptedConnection(e);var s={for:e.connection.remoteAddress||e.socket.remoteAddress,port:i.getPort(e),proto:o?"https":"http"};["for","port","proto"].forEach((function(t){e.headers["x-forwarded-"+t]=(e.headers["x-forwarded-"+t]||"")+(e.headers["x-forwarded-"+t]?",":"")+s[t]}));e.headers["x-forwarded-host"]=e.headers["x-forwarded-host"]||e.headers["host"]||""},stream:function stream(e,t,r,o,s,u){s.emit("start",e,t,r.target||r.forward);var f=r.followRedirects?a:c;var h=f.http;var p=f.https;if(r.forward){var d=(r.forward.protocol==="https:"?p:h).request(i.setupOutgoing(r.ssl||{},r,e,"forward"));var l=createErrorHandler(d,r.forward);e.on("error",l);d.on("error",l);(r.buffer||e).pipe(d);if(!r.target){return t.end()}}var v=(r.target.protocol==="https:"?p:h).request(i.setupOutgoing(r.ssl||{},r,e));v.on("socket",(function(o){if(s&&!v.getHeader("expect")){s.emit("proxyReq",v,e,t,r)}}));if(r.proxyTimeout){v.setTimeout(r.proxyTimeout,(function(){v.abort()}))}e.on("aborted",(function(){v.abort()}));var m=createErrorHandler(v,r.target);e.on("error",m);v.on("error",m);function createErrorHandler(r,o){return function proxyError(n){if(e.socket.destroyed&&n.code==="ECONNRESET"){s.emit("econnreset",n,e,t,o);return r.abort()}if(u){u(n,e,t,o)}else{s.emit("error",n,e,t,o)}}}(r.buffer||e).pipe(v);v.on("response",(function(o){if(s){s.emit("proxyRes",o,e,t)}if(!t.headersSent&&!r.selfHandleResponse){for(var i=0;i<n.length;i++){if(n[i](e,t,o,r)){break}}}if(!t.finished){o.on("end",(function(){if(s)s.emit("end",e,t,o)}));if(!r.selfHandleResponse)o.pipe(t)}else{if(s)s.emit("end",e,t,o)}}))}}},470:(e,t,r)=>{var o=r(310),s=r(29);var n=/^201|30(1|2|7|8)$/;
+ */e.exports={deleteLength:function deleteLength(e,t,r){if((e.method==="DELETE"||e.method==="OPTIONS")&&typeof e.headers["content-length"]==="undefined"&&typeof e.headers["transfer-encoding"]==="undefined"){e.headers["content-length"]="0"}},timeout:function timeout(e,t,r){if(r.timeout){e.socket.setTimeout(r.timeout)}},XHeaders:function XHeaders(e,t,r){if(!r.xfwd)return;var o=e.isSpdy||i.hasEncryptedConnection(e);var n={for:e.connection.remoteAddress||e.socket.remoteAddress,port:i.getPort(e),proto:o?"https":"http"};["for","port","proto"].forEach((function(t){e.headers["x-forwarded-"+t]=(e.headers["x-forwarded-"+t]||"")+(e.headers["x-forwarded-"+t]?",":"")+n[t]}));e.headers["x-forwarded-host"]=e.headers["x-forwarded-host"]||e.headers["host"]||""},stream:function stream(e,t,r,o,n,u){n.emit("start",e,t,r.target||r.forward);var f=r.followRedirects?a:c;var h=f.http;var p=f.https;if(r.forward){var d=(r.forward.protocol==="https:"?p:h).request(i.setupOutgoing(r.ssl||{},r,e,"forward"));var l=createErrorHandler(d,r.forward);e.on("error",l);d.on("error",l);(r.buffer||e).pipe(d);if(!r.target){return t.end()}}var v=(r.target.protocol==="https:"?p:h).request(i.setupOutgoing(r.ssl||{},r,e));v.on("socket",(function(o){if(n&&!v.getHeader("expect")){n.emit("proxyReq",v,e,t,r)}}));if(r.proxyTimeout){v.setTimeout(r.proxyTimeout,(function(){v.abort()}))}e.on("aborted",(function(){v.abort()}));var m=createErrorHandler(v,r.target);e.on("error",m);v.on("error",m);function createErrorHandler(r,o){return function proxyError(s){if(e.socket.destroyed&&s.code==="ECONNRESET"){n.emit("econnreset",s,e,t,o);return r.abort()}if(u){u(s,e,t,o)}else{n.emit("error",s,e,t,o)}}}(r.buffer||e).pipe(v);v.on("response",(function(o){if(n){n.emit("proxyRes",o,e,t)}if(!t.headersSent&&!r.selfHandleResponse){for(var i=0;i<s.length;i++){if(s[i](e,t,o,r)){break}}}if(!t.finished){o.on("end",(function(){if(n)n.emit("end",e,t,o)}));if(!r.selfHandleResponse)o.pipe(t)}else{if(n)n.emit("end",e,t,o)}}))}}},445:(e,t,r)=>{var o=r(310),n=r(341);var s=/^201|30(1|2|7|8)$/;
/*!
* Array of passes.
*
* A `pass` is just a function that is executed on `req, res, options`
* so that you can easily add new checks while still keeping the base
* flexible.
- */e.exports={removeChunked:function removeChunked(e,t,r){if(e.httpVersion==="1.0"){delete r.headers["transfer-encoding"]}},setConnection:function setConnection(e,t,r){if(e.httpVersion==="1.0"){r.headers.connection=e.headers.connection||"close"}else if(e.httpVersion!=="2.0"&&!r.headers.connection){r.headers.connection=e.headers.connection||"keep-alive"}},setRedirectHostRewrite:function setRedirectHostRewrite(e,t,r,s){if((s.hostRewrite||s.autoRewrite||s.protocolRewrite)&&r.headers["location"]&&n.test(r.statusCode)){var i=o.parse(s.target);var a=o.parse(r.headers["location"]);if(i.host!=a.host){return}if(s.hostRewrite){a.host=s.hostRewrite}else if(s.autoRewrite){a.host=e.headers["host"]}if(s.protocolRewrite){a.protocol=s.protocolRewrite}r.headers["location"]=a.format()}},writeHeaders:function writeHeaders(e,t,r,o){var n=o.cookieDomainRewrite,i=o.cookiePathRewrite,a=o.preserveHeaderKeyCase,c,setHeader=function(e,r){if(r==undefined)return;if(n&&e.toLowerCase()==="set-cookie"){r=s.rewriteCookieProperty(r,n,"domain")}if(i&&e.toLowerCase()==="set-cookie"){r=s.rewriteCookieProperty(r,i,"path")}t.setHeader(String(e).trim(),r)};if(typeof n==="string"){n={"*":n}}if(typeof i==="string"){i={"*":i}}if(a&&r.rawHeaders!=undefined){c={};for(var u=0;u<r.rawHeaders.length;u+=2){var f=r.rawHeaders[u];c[f.toLowerCase()]=f}}Object.keys(r.headers).forEach((function(e){var t=r.headers[e];if(a&&c){e=c[e]||e}setHeader(e,t)}))},writeStatusCode:function writeStatusCode(e,t,r){if(r.statusMessage){t.statusCode=r.statusCode;t.statusMessage=r.statusMessage}else{t.statusCode=r.statusCode}}}},558:(e,t,r)=>{var o=r(685),s=r(687),n=r(29);
+ */e.exports={removeChunked:function removeChunked(e,t,r){if(e.httpVersion==="1.0"){delete r.headers["transfer-encoding"]}},setConnection:function setConnection(e,t,r){if(e.httpVersion==="1.0"){r.headers.connection=e.headers.connection||"close"}else if(e.httpVersion!=="2.0"&&!r.headers.connection){r.headers.connection=e.headers.connection||"keep-alive"}},setRedirectHostRewrite:function setRedirectHostRewrite(e,t,r,n){if((n.hostRewrite||n.autoRewrite||n.protocolRewrite)&&r.headers["location"]&&s.test(r.statusCode)){var i=o.parse(n.target);var a=o.parse(r.headers["location"]);if(i.host!=a.host){return}if(n.hostRewrite){a.host=n.hostRewrite}else if(n.autoRewrite){a.host=e.headers["host"]}if(n.protocolRewrite){a.protocol=n.protocolRewrite}r.headers["location"]=a.format()}},writeHeaders:function writeHeaders(e,t,r,o){var s=o.cookieDomainRewrite,i=o.cookiePathRewrite,a=o.preserveHeaderKeyCase,c,setHeader=function(e,r){if(r==undefined)return;if(s&&e.toLowerCase()==="set-cookie"){r=n.rewriteCookieProperty(r,s,"domain")}if(i&&e.toLowerCase()==="set-cookie"){r=n.rewriteCookieProperty(r,i,"path")}t.setHeader(String(e).trim(),r)};if(typeof s==="string"){s={"*":s}}if(typeof i==="string"){i={"*":i}}if(a&&r.rawHeaders!=undefined){c={};for(var u=0;u<r.rawHeaders.length;u+=2){var f=r.rawHeaders[u];c[f.toLowerCase()]=f}}Object.keys(r.headers).forEach((function(e){var t=r.headers[e];if(a&&c){e=c[e]||e}setHeader(e,t)}))},writeStatusCode:function writeStatusCode(e,t,r){if(r.statusMessage){t.statusCode=r.statusCode;t.statusMessage=r.statusMessage}else{t.statusCode=r.statusCode}}}},761:(e,t,r)=>{var o=r(685),n=r(687),s=r(341);
/*!
* Array of passes.
*
* A `pass` is just a function that is executed on `req, socket, options`
* so that you can easily add new checks while still keeping the base
* flexible.
- */e.exports={checkMethodAndHeader:function checkMethodAndHeader(e,t){if(e.method!=="GET"||!e.headers.upgrade){t.destroy();return true}if(e.headers.upgrade.toLowerCase()!=="websocket"){t.destroy();return true}},XHeaders:function XHeaders(e,t,r){if(!r.xfwd)return;var o={for:e.connection.remoteAddress||e.socket.remoteAddress,port:n.getPort(e),proto:n.hasEncryptedConnection(e)?"wss":"ws"};["for","port","proto"].forEach((function(t){e.headers["x-forwarded-"+t]=(e.headers["x-forwarded-"+t]||"")+(e.headers["x-forwarded-"+t]?",":"")+o[t]}))},stream:function stream(e,t,r,i,a,c){var createHttpHeader=function(e,t){return Object.keys(t).reduce((function(e,r){var o=t[r];if(!Array.isArray(o)){e.push(r+": "+o);return e}for(var s=0;s<o.length;s++){e.push(r+": "+o[s])}return e}),[e]).join("\r\n")+"\r\n\r\n"};n.setupSocket(t);if(i&&i.length)t.unshift(i);var u=(n.isSSL.test(r.target.protocol)?s:o).request(n.setupOutgoing(r.ssl||{},r,e));if(a){a.emit("proxyReqWs",u,e,t,r,i)}u.on("error",onOutgoingError);u.on("response",(function(e){if(!e.upgrade){t.write(createHttpHeader("HTTP/"+e.httpVersion+" "+e.statusCode+" "+e.statusMessage,e.headers));e.pipe(t)}}));u.on("upgrade",(function(e,r,o){r.on("error",onOutgoingError);r.on("end",(function(){a.emit("close",e,r,o)}));t.on("error",(function(){r.end()}));n.setupSocket(r);if(o&&o.length)r.unshift(o);t.write(createHttpHeader("HTTP/1.1 101 Switching Protocols",e.headers));r.pipe(t).pipe(r);a.emit("open",r);a.emit("proxySocket",r)}));return u.end();function onOutgoingError(r){if(c){c(r,e,t)}else{a.emit("error",r,e,t)}t.end()}}}},85:e=>{"use strict";e.exports=function required(e,t){t=t.split(":")[0];e=+e;if(!e)return false;switch(t){case"http":case"ws":return e!==80;case"https":case"wss":return e!==443;case"ftp":return e!==21;case"gopher":return e!==70;case"file":return false}return e!==0}},491:e=>{"use strict";e.exports=require("assert")},685:e=>{"use strict";e.exports=require("http")},687:e=>{"use strict";e.exports=require("https")},937:e=>{"use strict";e.exports=require("next/dist/compiled/debug")},781:e=>{"use strict";e.exports=require("stream")},310:e=>{"use strict";e.exports=require("url")},837:e=>{"use strict";e.exports=require("util")}};var t={};function __nccwpck_require__(r){var o=t[r];if(o!==undefined){return o.exports}var s=t[r]={exports:{}};var n=true;try{e[r](s,s.exports,__nccwpck_require__);n=false}finally{if(n)delete t[r]}return s.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var r=__nccwpck_require__(413);module.exports=r})();
+ */e.exports={checkMethodAndHeader:function checkMethodAndHeader(e,t){if(e.method!=="GET"||!e.headers.upgrade){t.destroy();return true}if(e.headers.upgrade.toLowerCase()!=="websocket"){t.destroy();return true}},XHeaders:function XHeaders(e,t,r){if(!r.xfwd)return;var o={for:e.connection.remoteAddress||e.socket.remoteAddress,port:s.getPort(e),proto:s.hasEncryptedConnection(e)?"wss":"ws"};["for","port","proto"].forEach((function(t){e.headers["x-forwarded-"+t]=(e.headers["x-forwarded-"+t]||"")+(e.headers["x-forwarded-"+t]?",":"")+o[t]}))},stream:function stream(e,t,r,i,a,c){var createHttpHeader=function(e,t){return Object.keys(t).reduce((function(e,r){var o=t[r];if(!Array.isArray(o)){e.push(r+": "+o);return e}for(var n=0;n<o.length;n++){e.push(r+": "+o[n])}return e}),[e]).join("\r\n")+"\r\n\r\n"};s.setupSocket(t);if(i&&i.length)t.unshift(i);var u=(s.isSSL.test(r.target.protocol)?n:o).request(s.setupOutgoing(r.ssl||{},r,e));if(a){a.emit("proxyReqWs",u,e,t,r,i)}u.on("error",onOutgoingError);u.on("response",(function(e){if(!e.upgrade){t.write(createHttpHeader("HTTP/"+e.httpVersion+" "+e.statusCode+" "+e.statusMessage,e.headers));e.pipe(t)}}));u.on("upgrade",(function(e,r,o){r.on("error",onOutgoingError);r.on("end",(function(){a.emit("close",e,r,o)}));t.on("error",(function(){r.end()}));s.setupSocket(r);if(o&&o.length)r.unshift(o);t.write(createHttpHeader("HTTP/1.1 101 Switching Protocols",e.headers));r.pipe(t).pipe(r);a.emit("open",r);a.emit("proxySocket",r)}));return u.end();function onOutgoingError(r){if(c){c(r,e,t)}else{a.emit("error",r,e,t)}t.end()}}}},85:e=>{"use strict";e.exports=function required(e,t){t=t.split(":")[0];e=+e;if(!e)return false;switch(t){case"http":case"ws":return e!==80;case"https":case"wss":return e!==443;case"ftp":return e!==21;case"gopher":return e!==70;case"file":return false}return e!==0}},491:e=>{"use strict";e.exports=require("assert")},685:e=>{"use strict";e.exports=require("http")},687:e=>{"use strict";e.exports=require("https")},937:e=>{"use strict";e.exports=require("next/dist/compiled/debug")},781:e=>{"use strict";e.exports=require("stream")},310:e=>{"use strict";e.exports=require("url")},837:e=>{"use strict";e.exports=require("util")}};var t={};function __nccwpck_require__(r){var o=t[r];if(o!==undefined){return o.exports}var n=t[r]={exports:{}};var s=true;try{e[r](n,n.exports,__nccwpck_require__);s=false}finally{if(s)delete t[r]}return n.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var r=__nccwpck_require__(204);module.exports=r})();
patches/http-proxy@1.18.1.patch+87 0
@@ -0,0 +1,90 @@
+diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js
+index 6513e81d80d5250ea249ea833f819ece67897c7e..09143dd1fe4e67885f40ea916a6ea1ef3e3afa19 100644
+--- a/lib/http-proxy/common.js
+@@ -1,9 +1,9 @@
+ var common = exports,
+ url = require('url'),
+- extend = require('util')._extend,
+ required = require('requires-port');
+
+ var upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i,
++ hopByHopTransferEncodingHeader = /(^|,)\s*transfer-encoding\s*($|,)/i,
+ isSSL = /^https|wss/;
+
+ /**
+@@ -40,10 +40,10 @@ common.setupOutgoing = function(outgoing, options, req, forward) {
+ );
+
+ outgoing.method = options.method || req.method;
+- outgoing.headers = extend({}, req.headers);
++ outgoing.headers = Object.assign({}, req.headers);
+
+ if (options.headers){
+- extend(outgoing.headers, options.headers);
++ Object.assign(outgoing.headers, options.headers);
+ }
+
+ if (options.auth) {
+@@ -61,13 +61,22 @@ common.setupOutgoing = function(outgoing, options, req, forward) {
+
+ outgoing.agent = options.agent || false;
+ outgoing.localAddress = options.localAddress;
++ outgoing.headers = outgoing.headers || {};
++ var hasTransferEncodingHeader = Object.keys(outgoing.headers).some(function (header) {
++ return header.toLowerCase() === 'transfer-encoding'
++ && typeof outgoing.headers[header] !== 'undefined';
++ });
++
++ if (hasTransferEncodingHeader
++ || (typeof outgoing.headers.connection === 'string'
++ && hopByHopTransferEncodingHeader.test(outgoing.headers.connection))
++ ) { outgoing.headers.connection = 'close'; }
+
+ //
+ // Remark: If we are false and not upgrading, set the connection: close. This is the right thing to do
+ // as node core doesn't handle this COMPLETELY properly yet.
+ //
+ if (!outgoing.agent) {
+- outgoing.headers = outgoing.headers || {};
+ if (typeof outgoing.headers.connection !== 'string'
+ || !upgradeHeader.test(outgoing.headers.connection)
+ ) { outgoing.headers.connection = 'close'; }
+diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js
+index 977a4b3622b9eaac27689f06347ea4c5173a96cd..88b2d0fcfa03c3aafa47c7e6d38e64412c45a7cc 100644
+--- a/lib/http-proxy/index.js
+@@ -1,5 +1,4 @@
+ var httpProxy = module.exports,
+- extend = require('util')._extend,
+ parse_url = require('url').parse,
+ EE3 = require('eventemitter3'),
+ http = require('http'),
+@@ -47,9 +46,9 @@ function createRightProxy(type) {
+ args[cntr] !== res
+ ) {
+ //Copy global options
+- requestOptions = extend({}, options);
++ requestOptions = Object.assign({}, options);
+ //Overwrite with request options
+- extend(requestOptions, args[cntr]);
++ Object.assign(requestOptions, args[cntr]);
+
+ cntr--;
+ }
+diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js
+index 7ae735514190eea569c605fff7d27c045fe8d601..c7c25e7228b21c76b3c7115af82ddcbf13a8e3ec 100644
+--- a/lib/http-proxy/passes/web-incoming.js
+@@ -33,9 +33,9 @@ module.exports = {
+
+ deleteLength: function deleteLength(req, res, options) {
+ if((req.method === 'DELETE' || req.method === 'OPTIONS')
+- && !req.headers['content-length']) {
++ && typeof req.headers['content-length'] === 'undefined'
++ && typeof req.headers['transfer-encoding'] === 'undefined') {
+ req.headers['content-length'] = '0';
+- delete req.headers['transfer-encoding'];
+ }
+ },
+
pnpm-lock.yaml+7 4
@@ -28,6 +28,9 @@ patchedDependencies:
'@types/node@20.17.6':
hash: rvl3vkomen3tospgr67bzubfyu
path: patches/@types__node@20.17.6.patch
+ http-proxy@1.18.1:
+ hash: eyqcxg3pntyhqyqr5zytxa7pbi
+ path: patches/http-proxy@1.18.1.patch
stacktrace-parser@0.1.10:
hash: x5tdcojc7b5m2b5ojepbcdl36a
path: patches/stacktrace-parser@0.1.10.patch
@@ -356,7 +359,7 @@ importers:
version: 5.1.18
http-proxy:
specifier: 1.18.1
- version: 1.18.1
+ version: 1.18.1(patch_hash=eyqcxg3pntyhqyqr5zytxa7pbi)
husky:
specifier: 9.0.11
version: 9.0.11
@@ -1517,7 +1520,7 @@ importers:
version: 5.1.1
http-proxy:
specifier: 1.18.1
- version: 1.18.1
+ version: 1.18.1(patch_hash=eyqcxg3pntyhqyqr5zytxa7pbi)
http-proxy-agent:
specifier: 5.0.0
version: 5.0.0
@@ -29804,7 +29807,7 @@ snapshots:
http-proxy-middleware@2.0.7(@types/express@4.17.21):
dependencies:
'@types/http-proxy': 1.17.16
- http-proxy: 1.18.1
+ http-proxy: 1.18.1(patch_hash=eyqcxg3pntyhqyqr5zytxa7pbi)
is-glob: 4.0.3
is-plain-obj: 3.0.0
micromatch: 4.0.8
@@ -29813,7 +29816,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- http-proxy@1.18.1:
+ http-proxy@1.18.1(patch_hash=eyqcxg3pntyhqyqr5zytxa7pbi):
dependencies:
eventemitter3: 4.0.7
follow-redirects: 1.9.0
test/e2e/rewrite-request-smuggling/next.config.js+13 0
@@ -0,0 +1,13 @@
+/** @type {import('next').NextConfig} */
+const nextConfig = {
+ async rewrites() {
+ return [
+ {
+ source: '/rewrites/:path*',
+ destination: `http://127.0.0.1:${process.env.TEST_INTERMEDIARY_PORT}/rewrites/:path*`,
+ },
+ ]
+ },
+}
+
+module.exports = nextConfig
test/e2e/rewrite-request-smuggling/pages/index.tsx+3 0
@@ -0,0 +1,3 @@
+export default function Page() {
+ return <p>hello world</p>
+}
test/e2e/rewrite-request-smuggling/rewrite-request-smuggling.test.ts+234 0
@@ -0,0 +1,234 @@
+import net from 'net'
+import http from 'http'
+import { createNext, NextInstance } from 'e2e-utils'
+import { findPort, retry } from 'next-test-utils'
+
+describe('rewrite-request-smuggling', () => {
+ if ((global as any).isNextDeploy) {
+ it('should skip deploy', () => {})
+ return
+ }
+
+ let backend: http.Server
+ let backendPort: number
+ let intermediary: http.Server
+ let intermediaryPort: number
+ let next: NextInstance
+ const backendRequests: string[] = []
+
+ async function sendSmugglingPayload({
+ nextPort,
+ connectionHeader,
+ method = 'DELETE',
+ rewritePath = '/rewrites/poc',
+ }: {
+ nextPort: number
+ connectionHeader: string
+ method?: 'DELETE' | 'OPTIONS'
+ rewritePath?: string
+ }) {
+ const smuggledRequest = Buffer.from(
+ `GET /secret HTTP/1.1\r\nHost: 127.0.0.1:${nextPort}\r\n\r\n`,
+ 'latin1'
+ )
+ const chunkSize = Buffer.from(
+ `${smuggledRequest.length.toString(16).toUpperCase()}\r\n`,
+ 'latin1'
+ )
+
+ const payload = Buffer.concat([
+ Buffer.from(
+ `${method} ${rewritePath} HTTP/1.1\r\nHost: 127.0.0.1:${nextPort}\r\nTransfer-Encoding: chunked\r\nConnection: ${connectionHeader}\r\n\r\n`,
+ 'latin1'
+ ),
+ chunkSize,
+ smuggledRequest,
+ Buffer.from('\r\n0\r\n\r\n', 'latin1'),
+ ])
+
+ await new Promise<void>((resolve, reject) => {
+ const socket = net.createConnection({
+ host: '127.0.0.1',
+ port: nextPort,
+ })
+
+ socket.once('connect', () => {
+ socket.write(payload)
+ })
+ socket.once('error', reject)
+ socket.setTimeout(1000, () => socket.destroy())
+ socket.once('close', () => resolve())
+ })
+ }
+
+ beforeAll(async () => {
+ backendPort = await findPort()
+ intermediaryPort = await findPort()
+
+ backend = http.createServer((req, res) => {
+ backendRequests.push(`${req.method} ${req.url}`)
+
+ if (req.url?.startsWith('/rewrites/')) {
+ res.statusCode = 200
+ res.end('rewrite-ok')
+ return
+ }
+
+ if (req.url === '/secret') {
+ res.statusCode = 200
+ res.end('secret')
+ return
+ }
+
+ res.statusCode = 404
+ res.end('not-found')
+ })
+
+ intermediary = http.createServer((req, res) => {
+ const connectionHeader = Array.isArray(req.headers['connection'])
+ ? req.headers['connection'].join(',')
+ : req.headers['connection'] || ''
+ const hopByHopHeaders = connectionHeader
+ .split(',')
+ .map((h) => h.trim().toLowerCase())
+ .filter(Boolean)
+ const stripTransferEncodingUnconditionally =
+ req.url?.startsWith('/rewrites/non-rfc-strip') || false
+
+ const forwardHeaders: Record<string, string | string[]> = {}
+ for (const [key, value] of Object.entries(req.headers)) {
+ if (key === 'connection') continue
+ if (stripTransferEncodingUnconditionally && key === 'transfer-encoding')
+ continue
+ if (hopByHopHeaders.includes(key)) continue
+ if (value !== undefined) {
+ forwardHeaders[key] = value
+ }
+ }
+ forwardHeaders.connection = stripTransferEncodingUnconditionally
+ ? connectionHeader.toLowerCase().includes('close')
+ ? 'close'
+ : 'keep-alive'
+ : 'keep-alive'
+
+ const proxyReq = http.request(
+ {
+ hostname: '127.0.0.1',
+ port: backendPort,
+ method: req.method,
+ path: req.url,
+ headers: forwardHeaders,
+ },
+ (proxyRes) => {
+ res.writeHead(proxyRes.statusCode || 500, proxyRes.headers)
+ proxyRes.pipe(res)
+ }
+ )
+
+ proxyReq.on('error', () => {
+ res.statusCode = 502
+ res.end('Bad Gateway')
+ })
+
+ req.pipe(proxyReq)
+ })
+
+ await new Promise<void>((resolve, reject) => {
+ backend.listen(backendPort, '127.0.0.1', resolve)
+ backend.once('error', reject)
+ })
+
+ await new Promise<void>((resolve, reject) => {
+ intermediary.listen(intermediaryPort, '127.0.0.1', resolve)
+ intermediary.once('error', reject)
+ })
+
+ next = await createNext({
+ files: __dirname,
+ env: {
+ TEST_INTERMEDIARY_PORT: String(intermediaryPort),
+ },
+ })
+ })
+
+ afterAll(async () => {
+ await next?.destroy()
+ await new Promise<void>((resolve) => intermediary.close(() => resolve()))
+ await new Promise<void>((resolve) => backend.close(() => resolve()))
+ })
+
+ it('does not smuggle a second request when using keep-alive only', async () => {
+ backendRequests.length = 0
+
+ const nextPort = Number(new URL(next.url).port)
+ await sendSmugglingPayload({ nextPort, connectionHeader: 'keep-alive' })
+
+ await retry(async () => {
+ expect(backendRequests).toContain('DELETE /rewrites/poc')
+ })
+ expect(backendRequests).not.toContain('GET /secret')
+ })
+
+ it('does not smuggle a second request with keep-alive, upgrade', async () => {
+ backendRequests.length = 0
+
+ const nextPort = Number(new URL(next.url).port)
+ await sendSmugglingPayload({
+ nextPort,
+ connectionHeader: 'keep-alive, upgrade',
+ })
+
+ await retry(async () => {
+ expect(backendRequests).toContain('DELETE /rewrites/poc')
+ })
+ expect(backendRequests).not.toContain('GET /secret')
+ })
+
+ it('does not smuggle a second request with Transfer-Encoding, upgrade', async () => {
+ backendRequests.length = 0
+
+ const nextPort = Number(new URL(next.url).port)
+ await sendSmugglingPayload({
+ nextPort,
+ connectionHeader: 'Transfer-Encoding, upgrade',
+ })
+
+ await retry(async () => {
+ expect(backendRequests).toContain('DELETE /rewrites/poc')
+ })
+ expect(backendRequests).not.toContain('GET /secret')
+ })
+
+ it('does not smuggle a second request for OPTIONS with Transfer-Encoding, upgrade', async () => {
+ backendRequests.length = 0
+
+ const nextPort = Number(new URL(next.url).port)
+ await sendSmugglingPayload({
+ nextPort,
+ method: 'OPTIONS',
+ connectionHeader: 'Transfer-Encoding, upgrade',
+ })
+
+ await retry(async () => {
+ expect(backendRequests).toContain('OPTIONS /rewrites/poc')
+ })
+ expect(backendRequests).not.toContain('GET /secret')
+ })
+
+ it('does not smuggle a second request when an intermediary strips transfer-encoding unconditionally', async () => {
+ backendRequests.length = 0
+
+ const nextPort = Number(new URL(next.url).port)
+ await sendSmugglingPayload({
+ nextPort,
+ method: 'OPTIONS',
+ rewritePath: '/rewrites/non-rfc-strip',
+ connectionHeader: 'keep-alive, upgrade',
+ })
+
+ await retry(async () => {
+ expect(backendRequests).toContain('OPTIONS /rewrites/non-rfc-strip')
+ })
+ expect(backendRequests).not.toContain('GET /secret')
+ })
+})

References