@@ -113,6 +113,92 @@ describe('fixRequestBody', () => {
113113 expect ( proxyRequest . write ) . toHaveBeenCalledWith ( expectedBody ) ;
114114 } ) ;
115115
116+ it ( 'should reject multipart field values containing CRLF' , ( ) => {
117+ const proxyRequest = fakeProxyRequest ( ) ;
118+ proxyRequest . setHeader ( 'content-type' , 'multipart/form-data; boundary=BB' ) ;
119+
120+ fixRequestBody (
121+ proxyRequest ,
122+ createRequestWithBody ( {
123+ user : 'alice\r\n--BB\r\nContent-Disposition: form-data; name="role"\r\n\r\nadmin' ,
124+ } ) ,
125+ ) ;
126+
127+ expect ( proxyRequest . write ) . toHaveBeenCalledTimes ( 0 ) ;
128+ expect ( proxyRequest . destroy ) . toHaveBeenCalledTimes ( 1 ) ;
129+ } ) ;
130+
131+ it ( 'should reject multipart field values containing LF only' , ( ) => {
132+ const proxyRequest = fakeProxyRequest ( ) ;
133+ proxyRequest . setHeader ( 'content-type' , 'multipart/form-data; boundary=BB' ) ;
134+
135+ fixRequestBody (
136+ proxyRequest ,
137+ createRequestWithBody ( {
138+ user : 'alice\nadmin' ,
139+ } ) ,
140+ ) ;
141+
142+ expect ( proxyRequest . write ) . toHaveBeenCalledTimes ( 0 ) ;
143+ expect ( proxyRequest . destroy ) . toHaveBeenCalledTimes ( 1 ) ;
144+ } ) ;
145+
146+ it ( 'should reject multipart field values containing CR only' , ( ) => {
147+ const proxyRequest = fakeProxyRequest ( ) ;
148+ proxyRequest . setHeader ( 'content-type' , 'multipart/form-data; boundary=BB' ) ;
149+
150+ fixRequestBody (
151+ proxyRequest ,
152+ createRequestWithBody ( {
153+ user : 'alice\radmin' ,
154+ } ) ,
155+ ) ;
156+
157+ expect ( proxyRequest . write ) . toHaveBeenCalledTimes ( 0 ) ;
158+ expect ( proxyRequest . destroy ) . toHaveBeenCalledTimes ( 1 ) ;
159+ } ) ;
160+
161+ it ( 'should reject multipart field names containing LF' , ( ) => {
162+ const proxyRequest = fakeProxyRequest ( ) ;
163+ proxyRequest . setHeader ( 'content-type' , 'multipart/form-data; boundary=BB' ) ;
164+
165+ fixRequestBody (
166+ proxyRequest ,
167+ createRequestWithBody ( {
168+ 'bad\nname' : 'alice' ,
169+ } ) ,
170+ ) ;
171+
172+ expect ( proxyRequest . write ) . toHaveBeenCalledTimes ( 0 ) ;
173+ expect ( proxyRequest . destroy ) . toHaveBeenCalledTimes ( 1 ) ;
174+ } ) ;
175+
176+ it ( 'should reject multipart field values containing the active boundary delimiter' , ( ) => {
177+ const proxyRequest = fakeProxyRequest ( ) ;
178+ proxyRequest . setHeader ( 'content-type' , 'multipart/form-data; boundary=BB' ) ;
179+
180+ fixRequestBody (
181+ proxyRequest ,
182+ createRequestWithBody ( {
183+ user : '--BB' ,
184+ } ) ,
185+ ) ;
186+
187+ expect ( proxyRequest . write ) . toHaveBeenCalledTimes ( 0 ) ;
188+ expect ( proxyRequest . destroy ) . toHaveBeenCalledTimes ( 1 ) ;
189+ } ) ;
190+
191+ it ( 'should escape quotes in multipart field names' , ( ) => {
192+ const proxyRequest = fakeProxyRequest ( ) ;
193+ proxyRequest . setHeader ( 'content-type' , 'multipart/form-data; boundary=BB' ) ;
194+
195+ fixRequestBody ( proxyRequest , createRequestWithBody ( { 'field"name' : 'value' } ) ) ;
196+
197+ expect ( proxyRequest . write ) . toHaveBeenCalledWith (
198+ '--BB\r\nContent-Disposition: form-data; name="field\\"name"\r\n\r\nvalue\r\n' ,
199+ ) ;
200+ } ) ;
201+
116202 it ( 'should write when body is not empty and Content-Type ends with +json' , ( ) => {
117203 const proxyRequest = fakeProxyRequest ( ) ;
118204 proxyRequest . setHeader ( 'content-type' , 'application/merge-patch+json; charset=utf-8' ) ;
0 commit comments