Safeguard
Application Security

Two Correct Parsers Can Disagree About the Same Multipart Request

A duplicate field name, an unusual boundary, a malformed header. Two standards-compliant parsers can resolve the same ambiguous bytes differently, and if a validator reads one interpretation while your application reads another, validation passed something it never actually checked.

Priya Raman
Staff Security Engineer
7 min read

Your API accepts a multipart form upload: a file, alongside a few regular fields like a description or a category. The parsing library reads the whole thing, gives you back a neat object with the fields and the file, and everything works. What that neat object does not tell you is whether two different parts of your stack agree on what it contains.

Multipart parsing is not one specification implemented identically everywhere. It is a loosely defined format with enough ambiguity that two correct, standards-compliant parsers can disagree about the same request, and that disagreement is where a specific, quiet class of bugs lives.

This post is about what happens when the layers in front of your application do not parse a request the same way your application does.

Where the disagreement comes from

A multipart request is a sequence of parts separated by a boundary string the client chooses and declares in a header. Parsers have to decide how to handle a request with duplicate field names, parts with unusual or malformed headers, boundaries that appear inside what should be file content, or field values containing characters the specification treats ambiguously.

None of these are exotic inputs. They are the kind of malformed-but-plausible request that a fuzzer produces easily and that a normal client, through a bug rather than malice, occasionally sends too. Different parsers, in different languages, at different layers of your stack, resolve these ambiguities differently, because the specification permits more than one reasonable interpretation.

Why this becomes a security problem specifically

A web application firewall or a validation layer inspects the request using one parser's interpretation, and your application processes it using another's. If a request contains a field twice with different values, and your validation layer reads the first occurrence while your application code reads the last, an attacker can put a benign value where the validator looks and the actual malicious value where your application looks. The validation passed a request that was never actually checked.

A reverse proxy or CDN parses the multipart boundary differently from your backend, particularly around edge cases like a boundary that appears within binary file content, or unusual whitespace around the boundary declaration. Content that one layer believes is inside a file part and another believes has terminated that part and started a new one produces two different reconstructions of the same request from a single set of bytes.

Field name collisions between the intended form field and a name that maps to something else entirely in your application's data model, when parsing is lenient about what characters are permitted in a field name, and where your application code interpolates parsed field names into something more structurally significant than a simple key lookup, such as a database column or an object property.

The general pattern underneath this

This is the same shape as the difference between how a load balancer reads a forwarded header and how your application reads it, or the difference between how a CI platform matches a secret for masking and what actually appears in a log. Whenever two systems separately interpret the same input, and only one of them is doing the actual security-relevant work, the interpretation gap between them is where a bypass lives, regardless of the specific format involved.

Multipart parsing is a particularly rich source of this because it has a genuinely large number of edge cases relative to how simple it appears, and because the layers in front of an application, proxies, gateways, firewalls, are frequently running an entirely different parsing implementation than the application framework behind them, often in a different language, maintained by a different team, updated on a different schedule.

What actually reduces the exposure

Minimise the number of distinct parsers a single request passes through before reaching the code that makes a security decision about it. Every additional layer that independently parses the request is an additional opportunity for its interpretation to diverge from the one that matters. Where a validation or filtering layer exists specifically to inspect multipart content, confirm it uses the same parsing library, or at minimum the same parsing behaviour on the specific edge cases that matter, as the application it is protecting.

Reject rather than tolerate ambiguous input. A parser configured to fail loudly on a duplicate field name, a malformed boundary, or an unrecognised header, rather than picking an interpretation and proceeding silently, removes the ambiguity entirely rather than resolving it in a way that might not match what another layer decided. Strict parsing is less convenient for tolerating slightly broken clients and it removes an entire category of this problem.

Treat field names and values from multipart requests as untrusted the same way you would any other form input, rather than assuming that because the transport format is more structured than a simple query string, the content within it deserves less scrutiny. The structure of the format has nothing to do with the trustworthiness of what is inside it.

Log the raw request alongside the parsed result during any investigation, so that if a discrepancy between what was sent and what your application believed was sent ever needs to be diagnosed, you have both representations to compare rather than only the parsed output that may already reflect the ambiguity you are trying to find.

Check yours

If you operate a proxy, gateway, or web application firewall in front of an application that accepts multipart uploads, and that layer performs any inspection or filtering, construct a request with a duplicate field name and check what each layer reports having received. A discrepancy is not automatically an exploitable bypass, but it is the specific condition that this entire class of bug depends on, and its presence is worth knowing about deliberately rather than discovering during an investigation into something that already went wrong.

The concession

Fully unifying parsing behaviour across every layer of a request path, when those layers are separate products maintained by separate vendors or teams, is often not practical, and strict rejection of ambiguous input has a real cost in compatibility with clients that are slightly non-conformant but otherwise harmless. Not every organisation can or should rebuild their edge infrastructure around this specific concern.

The proportionate response is awareness at the point where it matters most: any layer making a security decision, a filter, a validator, an authorization check, based on multipart content should be the same layer, or use verifiably the same parsing behaviour, as whatever ultimately acts on that content. Everywhere else, the difference in interpretation is unlikely to matter, because nothing downstream is treating the parsed result as authoritative for a decision.

The implication

Two parsers that are each individually correct, according to a specification loose enough to permit more than one reasonable reading, can still disagree about a single request, and that disagreement is invisible until someone constructs a request specifically designed to land differently on each side.

If a validation or filtering layer sits in front of your application and inspects multipart content, that is worth treating as a question rather than an assumption: does it see the same request your application code actually processes, checked directly rather than reasoned about from the outside.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.