Skip to content

[BUG] fatal error: concurrent map writes in MultiPartForm.Decode during fuzzing #6947

@yusei-wy

Description

@yusei-wy

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:106

Environment

  • 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions