In the previous part, we mapped OpenBMC as a layered system. Now we can zoom into one of the most important edge services: bmcweb.
bmcweb is interesting because it sits in front of Redfish and the WebUI. That means it accepts HTTPS traffic, parses HTTP, handles routes, and then talks to internal OpenBMC services. If this component crashes, the BMC may still be alive, but the main remote management path becomes unreliable. If memory corruption is reachable, the situation gets more serious.
This post looks at CVE-2022-2809 and CVE-2022-3409. I will keep the write-up defensive and avoid publishing a full copy-paste exploit. The point is to understand the bug shape, the parser failure, and what a good patch looks like.

The Short Version
The affected component is bmcweb’s multipart_parser. The vulnerable versions are OpenBMC 2.12 and earlier. The official GitHub advisory says the issue is fixed in OpenBMC 2.13.

The trigger is a malformed multipart form body. More specifically, a long header-like line appears inside a multipart part, but it does not follow normal Key: Value header syntax. Under fuzzing and sanitizer builds, this exposed out-of-bounds writes. In practical terms, the advisory describes denial of service through repeated requests, and sanitizer output showed memory corruption behavior.
The important details:
| Item | Detail |
|---|---|
| Component | bmcweb |
| Affected versions | OpenBMC 2.12 and earlier |
| Fixed version | OpenBMC 2.13 |
| CVEs | CVE-2022-2809, CVE-2022-3409 |
| Bug class | Out-of-bounds write, heap/stack buffer overflow, improper handling of values |
| Trigger shape | Multipart form data with malformed, long, unclosed part header input |
| Impact | bmcweb denial of service, with memory corruption observable in fuzzing/sanitizer setups |
| Authentication | Described by the advisory as unauthenticated |
NVD describes both CVEs as denial-of-service vulnerabilities in bmcweb. The OpenBMC advisory rates the issue High with CVSS 8.2.
Why Multipart Is Easy To Get Wrong
multipart/form-data looks boring if you only see valid requests. It becomes annoying when you write the parser.

A normal request looks roughly like this:
POST /upload HTTP/1.1
Host: example.com
Content-Type: multipart/form-data; boundary=BOUNDARY
Content-Length: ...
--BOUNDARY
Content-Disposition: form-data; name="file"; filename="a.txt"
Content-Type: text/plain
hello world
--BOUNDARY--
The parser has to track several things at once:
- the boundary declared in the HTTP header
- boundary lines inside the body
- per-part headers
- CRLF sequences
- the empty line between headers and body
- arbitrary body data
- final boundary termination
- malformed or truncated input at every state
The state machine slide is the one that made the bug easier to understand for me. The parser moves from boundary matching, into header parsing, into part data, then back to boundary handling.

If a transition assumes input exists but the buffer is already exhausted, you get an out-of-range read or write. If a malformed header sends the state machine into a path the author did not expect, you get weird edge cases. That is exactly the kind of thing fuzzers are good at finding.
What The Malformed Request Does
The lab in the slide deck targets an OpenBMC 2.12 environment. The malformed request goes to a web route and carries a multipart body. The interesting part is not the route itself. The interesting part is the body shape.
Instead of a clean part header like:
Content-Disposition: form-data; name="file"
the body contains a long header-like line without the colon that would normally split a header name from a value.
Conceptually:
--<boundary>
<very long malformed header-like line without a colon>
I am intentionally not including the full proof-of-concept code here. The behavior is already documented publicly, and the defensive lesson does not require turning the post into a ready-made crash script.
A Quick Stack Refresher
Before going further, it helps to refresh stack frames and buffer overflow basics. CVE write-ups can otherwise jump too quickly from “bad parser state” to “memory corruption” without showing what actually gets damaged.

When a function is called, the CPU and compiler cooperate to keep track of local variables, saved frame pointers, and return addresses. The exact layout depends on architecture and compiler settings, but the mental model is stable: a function needs somewhere to put temporary state, and it needs to know where to return.


In a classic stack overflow, input intended for a local buffer grows past the buffer boundary and starts overwriting neighboring data.

The slide sequence shows the idea visually: first the input fills the buffer, then it moves into adjacent space, and eventually it can overwrite control data such as the return address.


For these bmcweb CVEs, the official advisory emphasizes denial of service and sanitizer-observed memory corruption. I would still treat that seriously. A one-byte overwrite is not a cute bug. It means the parser wrote somewhere it did not own.
Root Cause Pattern
The root issue is not “multipart is insecure.” The root issue is a hand-written parser that did not reject malformed input cleanly enough.
The fixing commit, 18e3f7f, addressed several parser edge cases:
- index access could go out of range
- a header without a colon could put the parser in an invalid state
- content after a boundary needed clearer handling
- missing final boundaries needed explicit errors
- malformed cases needed tests, not just code changes

The patch adds explicit parser errors such as:
ERROR_UNEXPECTED_END_OF_HEADER
ERROR_UNEXPECTED_END_OF_INPUT
ERROR_OUT_OF_RANGE
That may look small, but this is the kind of patch I like to see. Bad input should become a boring parser error, not a crash.
The added tests are also important:

Without tests, parser fixes are easy to regress. A future refactor can accidentally re-open the same edge case.
What I Would Do
In a lab, I would keep the bmcweb logs open while sending malformed multipart requests:
journalctl -u bmcweb -f
systemctl status bmcweb
If bmcweb restarts after a malformed request, that is already enough signal to stop and inspect the parser path. In production, I would not overcomplicate the first response: use firmware with the patched bmcweb, and make sure BMC HTTPS is only reachable from the management network. If random user machines can hit the BMC web service, the exposure is already too wide.
For the code itself, the defensive rule is also simple. Test the ugly cases: headers without colons, truncated input, strange CRLF placement, missing final boundaries, and oversized fields. Then run the parser under sanitizers and fuzz it. This is the kind of parser where “almost correct” is not good enough.
The lesson here is very practical: parsers should fail closed. If the parser cannot prove that the next byte exists and belongs to the current state, it should return an error immediately.
Next, we move from HTTPS to UDP and look at slpd-lite.