-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Description
Is there an existing issue for this?
- I have searched the existing issues.
Current Behavior
When running fuzzing templates with concurrency > 1 against targets with multipart/form-data bodies, MultiPartForm.Decode in pkg/fuzz/dataformat/multipart.go causes fatal error: concurrent map writes. This is unrecoverable — the Go runtime kills the process immediately.
Expected Behavior
Fuzzing with multipart/form-data bodies should work correctly under concurrent execution without crashing.
Steps To Reproduce
func TestMultiPartFormDecode_RaceCondition(t *testing.T) {
mpf := dataformat.NewMultiPartForm()
boundary := "boundary123"
body := "--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"file\"; filename=\"test.txt\"\r\n" +
"Content-Type: text/plain\r\n\r\n" +
"file content\r\n" +
"--" + boundary + "--\r\n"
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mpf.ParseBoundary("multipart/form-data; boundary=" + boundary)
mpf.Decode(body)
}()
}
wg.Wait()
}Run with go test -race ./pkg/fuzz/dataformat/...
Relevant log output
fatal error: concurrent map writes
goroutine N [running]:
github.com/projectdiscovery/nuclei/v3/pkg/fuzz/dataformat.(*MultiPartForm).Decode(...)
pkg/fuzz/dataformat/multipart.go:222
github.com/projectdiscovery/nuclei/v3/pkg/fuzz/component.(*Body).parseBody(...)
pkg/fuzz/component/body.go:87
github.com/projectdiscovery/nuclei/v3/pkg/fuzz/component.(*Body).Parse(...)
pkg/fuzz/component/body.go:68
github.com/projectdiscovery/nuclei/v3/pkg/fuzz.(*Rule).Execute(...)
pkg/fuzz/execute.go:106Environment
- OS: linux (Cloud Run), also reproducible on macOS
- Nuclei: v3.6.2 (also affects dev branch)
- Go: 1.25.5
Anything else?
Root Cause: MultiPartForm is registered as a singleton in dataformat.init() and shared across all goroutines via dataformat.Get(). Its Decode() method writes to the filesMetadata map and ParseBoundary() writes to the boundary field, both without synchronization.
Proposed Fix: Create a fresh MultiPartForm instance per parse in Body.parseBody instead of reusing the singleton, since MultiPartForm is the only stateful DataFormat implementation.
This is similar to the fix in #6828 which addressed concurrent map writes in evaluateVarsWithInteractsh.