Skip to content

fix: handle duplicate field names in multipart form encoding#6402

Closed
yusei-wy wants to merge 2 commits intoprojectdiscovery:devfrom
yusei-wy:fix/multipart-duplicate-fields
Closed

fix: handle duplicate field names in multipart form encoding#6402
yusei-wy wants to merge 2 commits intoprojectdiscovery:devfrom
yusei-wy:fix/multipart-duplicate-fields

Conversation

@yusei-wy
Copy link
Contributor

@yusei-wy yusei-wy commented Aug 20, 2025

Proposed changes

Fix panic when encoding multipart forms with duplicate field names during DAST fuzzing.

Problem: The fuzzing module would panic with "interface conversion: interface {} is []string, not string" when processing forms with duplicate field names (common in checkboxes and multi-select elements).

Root Cause:

  • Decode method correctly stores duplicate fields as []string
  • Encode method incorrectly assumes all values are string type
  • Results in type assertion failure causing panic

Solution:

  1. Added type-safe handling in MultiPartForm.Encode() to process both string and []string values
  2. Refactored code to reduce duplication
  3. Added comprehensive tests including real-world checkbox use cases

Fixes #6401

Checklist

  • Pull request is created against the dev branch
  • All checks passed (lint, unit/integration/regression tests etc.) with my changes
  • I have added tests that prove my fix is effective or that my feature works
  • I have added necessary documentation (if appropriate)

Summary by CodeRabbit

  • New Features

    • Multipart form encoding now supports multiple values per field (duplicate keys), normalizes various value types to strings, preserves file attachment behavior, and improves per-value error handling.
  • Tests

    • Added tests validating multi-value fields, single-value backward compatibility, mixed-type handling, omission of empty arrays, and full encode/decode round-trip with deterministic ordering.

@auto-assign auto-assign bot requested a review from dwisiswant0 August 20, 2025 02:46
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 20, 2025

Walkthrough

Encode now normalizes form values to support strings, []string and []any, writing one multipart part per value and handling errors per part. Added unit tests covering duplicates, single-string compatibility, mixed types, empty arrays, and an encode/decode round-trip.

Changes

Cohort / File(s) Summary of Changes
Multipart encoding logic
pkg/fuzz/dataformat/multipart.go
Normalize values: map string → []string{v}, []string → itself, []any → []string via fmt.Sprint, default via fmt.Sprint. Iterate over each string value to CreateFormField and Write; set Itererr and return false on any error. File-attachment handling unchanged.
Multipart tests
pkg/fuzz/dataformat/multipart_test.go
Add tests: table-driven Encode cases (duplicate fields as []string, single-string compatibility, mixed types including numbers, omit empty arrays) and an Encode/Decode round-trip. Uses deterministic boundary and ordered map for assertions.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant MultiPartForm
  participant MIMEWriter as multipart.Writer

  Caller->>MultiPartForm: Encode(fields, boundary)
  MultiPartForm->>MultiPartForm: Normalize each field value to []string
  loop for each key
    loop for each value in []string
      MultiPartForm->>MIMEWriter: CreateFormField(key)
      alt create success
        MultiPartForm->>MIMEWriter: Write(value)
        alt write success
          Note right of MIMEWriter #A3D3A3: part written
        else write error
          MultiPartForm-->>Caller: return false (Itererr set)
        end
      else create error
        MultiPartForm-->>Caller: return false (Itererr set)
      end
    end
  end
  MultiPartForm-->>Caller: return true
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Assessment against linked issues

Objective Addressed Explanation
Handle duplicate multipart field names without panic; process []string from Decode in Encode (#6401)
Encode both string and []string values per RFC 7578; create separate parts per value (#6401)
Add safeguards to avoid interface conversion panic at multipart.go:85 (#6401)
Maintain backward compatibility for single-string fields (#6401)

I hopped through fields with names the same,
No more panics—each value plays the game.
Parts lined up, written one by one,
Boundaries hum, the round-trip's done.
A rabbit nods: "Fuzzing now is fun!" 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 25225bd and f5957f2.

📒 Files selected for processing (1)
  • pkg/fuzz/dataformat/multipart.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/fuzz/dataformat/multipart.go
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
pkg/fuzz/dataformat/multipart.go (4)

81-89: Add explicit []byte handling to avoid surprising fmt.Sprint output

fmt.Sprint on []byte yields a space-separated numeric list (e.g., "[65 66]") instead of the intended string content. Treating []byte as text is a safer default for form fields.

Apply this diff:

 		switch v := value.(type) {
 		case string:
 			values = []string{v}
 		case []string:
 			values = v
+		case []byte:
+			// Treat raw bytes as text for standard form fields
+			values = []string{string(v)}
 		default:
 			// Fallback: attempt string conversion
 			values = []string{fmt.Sprint(v)}

97-99: Micro-opt: avoid alloc with io.WriteString

Using io.WriteString avoids allocating a new []byte for each value.

Apply this diff:

-			if _, err = fw.Write([]byte(val)); err != nil {
+			if _, err = io.WriteString(fw, val); err != nil {

108-110: Don’t ignore Close() error on multipart.Writer

Close writes the final boundary and can fail. Bubble the error up instead of discarding it.

You can update this part as follows:

if err := w.Close(); err != nil {
	return "", err
}
return b.String(), nil

43-45: Allow default boundary when unset

SetBoundary rejects empty strings. If boundary isn’t provided, let multipart.Writer use its safe, generated default.

Suggested adjustment:

// Only override when user explicitly provided a boundary
if m.boundary != "" {
	if err := w.SetBoundary(m.boundary); err != nil {
		return "", err
	}
}
pkg/fuzz/dataformat/multipart_test.go (1)

12-17: Assert absence for empty arrays to match test intent

The case name says the empty array “should not appear,” but we don’t currently assert its absence. Add a notContains contract to the table and verify it.

Apply these diffs:

 type TestMultiPartFormEncode(t *testing.T) {
 	tests := []struct {
 		name     string
 		fields   map[string]any
 		wantErr  bool
-		contains []string // strings that should appear in encoded output
+		contains    []string // strings that should appear in encoded output
+		notContains []string // strings that must not appear in encoded output
 	}{
 		{
 			name: "empty array - should not appear in output",
 			fields: map[string]any{
 				"emptyArray":  []string{},
 				"normalField": "value",
 			},
-			contains: []string{"normalField", "value"},
+			contains:    []string{"normalField", "value"},
+			notContains: []string{"emptyArray"},
 		},
 			require.NoError(t, err)
 			for _, expected := range tt.contains {
 				assert.Contains(t, encoded, expected)
 			}
+			for _, unexpected := range tt.notContains {
+				assert.NotContains(t, encoded, unexpected)
+			}

Also applies to: 44-50, 70-74

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b4644af and 25225bd.

📒 Files selected for processing (2)
  • pkg/fuzz/dataformat/multipart.go (1 hunks)
  • pkg/fuzz/dataformat/multipart_test.go (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
pkg/fuzz/dataformat/multipart_test.go (2)
pkg/fuzz/dataformat/multipart.go (1)
  • NewMultiPartForm (29-31)
pkg/fuzz/dataformat/kv.go (1)
  • KVOrderedMap (105-107)
🔇 Additional comments (2)
pkg/fuzz/dataformat/multipart.go (1)

79-101: Solid fix: normalize to []string and iterate to avoid type assertion panic

This cleanly handles both string and []string, prevents the panic, and preserves multi-value semantics. Error propagation on each write is correct.

pkg/fuzz/dataformat/multipart_test.go (1)

11-51: Good coverage and realistic scenarios

Covers duplicates ([]string), single-field compatibility, mixed types (fallback), and empty arrays. Deterministic boundary plus substring checks make the tests robust to ordering differences.

- Add support for []any type to create separate fields for each element
- Fix issue where arrays were converted to single string representation
- Maintain backward compatibility for string and []string types
@dwisiswant0
Copy link
Member

Superseded by #6404

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Panic on duplicate multipart form field names during fuzzing

2 participants