@@ -139,6 +139,88 @@ func TestTryExtractBody(t *testing.T) {
139139 })
140140}
141141
142+ func TestTryExtractBodyBypassVectors (t * testing.T ) {
143+ t .Run ("empty JSON object prefix does not suppress multipart field extraction" , func (t * testing.T ) {
144+ body := & bytes.Buffer {}
145+ writer := multipart .NewWriter (body )
146+ _ = writer .WriteField ("name" , "injected" )
147+ writer .Close ()
148+
149+ req := httptest .NewRequest (http .MethodPost , "/test" , strings .NewReader ("{}\n " + body .String ()))
150+ req .Header .Set ("Content-Type" , writer .FormDataContentType ())
151+
152+ parser := & mockParser {req : req }
153+ result := TryExtractBody (req , parser )
154+
155+ formValues , ok := result .(url.Values )
156+ require .True (t , ok , "expected url.Values for multipart/form-data request, got %T: %v" , result , result )
157+ assert .Equal (t , "injected" , formValues .Get ("name" ))
158+ })
159+
160+ t .Run ("non-empty JSON object prefix does not suppress multipart field extraction" , func (t * testing.T ) {
161+ body := & bytes.Buffer {}
162+ writer := multipart .NewWriter (body )
163+ _ = writer .WriteField ("name" , "injected" )
164+ writer .Close ()
165+
166+ req := httptest .NewRequest (http .MethodPost , "/test" , strings .NewReader (`{"key":"val"}` + "\n " + body .String ()))
167+ req .Header .Set ("Content-Type" , writer .FormDataContentType ())
168+
169+ parser := & mockParser {req : req }
170+ result := TryExtractBody (req , parser )
171+
172+ formValues , ok := result .(url.Values )
173+ require .True (t , ok , "expected url.Values for multipart/form-data request, got %T: %v" , result , result )
174+ assert .Equal (t , "injected" , formValues .Get ("name" ))
175+ })
176+
177+ t .Run ("empty JSON array prefix does not suppress multipart field extraction" , func (t * testing.T ) {
178+ body := & bytes.Buffer {}
179+ writer := multipart .NewWriter (body )
180+ _ = writer .WriteField ("name" , "injected" )
181+ writer .Close ()
182+
183+ req := httptest .NewRequest (http .MethodPost , "/test" , strings .NewReader ("[]\n " + body .String ()))
184+ req .Header .Set ("Content-Type" , writer .FormDataContentType ())
185+
186+ parser := & mockParser {req : req }
187+ result := TryExtractBody (req , parser )
188+
189+ formValues , ok := result .(url.Values )
190+ require .True (t , ok , "expected url.Values for multipart/form-data request, got %T: %v" , result , result )
191+ assert .Equal (t , "injected" , formValues .Get ("name" ))
192+ })
193+
194+ t .Run ("JSON body is scanned even when Content-Type is multipart" , func (t * testing.T ) {
195+ req := httptest .NewRequest (http .MethodPost , "/test" , strings .NewReader (`{"name":"injected"}` ))
196+ req .Header .Set ("Content-Type" , "multipart/form-data; boundary=----boundary" )
197+
198+ parser := & mockParser {req : req }
199+ result := TryExtractBody (req , parser )
200+
201+ resultMap , ok := result .(map [string ]interface {})
202+ require .True (t , ok , "expected map, got %T: %v" , result , result )
203+ assert .Equal (t , "injected" , resultMap ["name" ])
204+ })
205+
206+ t .Run ("NDJSON body returns all objects for inspection" , func (t * testing.T ) {
207+ body := `{"payload":"safe"}` + "\n " + `{"payload":"danger"}`
208+ req := httptest .NewRequest (http .MethodPost , "/test" , strings .NewReader (body ))
209+ req .Header .Set ("Content-Type" , "application/json" )
210+
211+ parser := & mockParser {req : req }
212+ result := TryExtractBody (req , parser )
213+
214+ resultSlice , ok := result .([]interface {})
215+ require .True (t , ok , "expected []interface{} for NDJSON body, got %T: %v" , result , result )
216+ require .Len (t , resultSlice , 2 )
217+
218+ second , ok := resultSlice [1 ].(map [string ]interface {})
219+ require .True (t , ok , "expected second element to be a map" )
220+ assert .Equal (t , "danger" , second ["payload" ])
221+ })
222+ }
223+
142224func TestBodyStillReadableAfterExtraction (t * testing.T ) {
143225 t .Run ("body readable after form extraction" , func (t * testing.T ) {
144226 formData := url.Values {}
0 commit comments