HexBrain

curl · Report #3973245

55: Heap-buffer-overflow read in `curl_formadd_ccsid()` with binary form data

Informativestatus
23upvotes
10 Sept 2026disclosed

How it was found

Summary

curl_formadd_ccsid() in projects/OS400/ccsidcurl.c performs a heap-buffer-overflow read when CURLFORM_CONTENTTYPE appears before an explicit length (CURLFORM_CONTENTLEN / CURLFORM_CONTENTSLENGTH) for binary CURLFORM_COPYCONTENTS data containing embedded NUL bytes. The overread bytes are copied into the generated multipart form body.

Affected versions

IBM i/OS400-specific API in curl 7.17.0 through 8.21.0, plus affected 8.22.0 prerelease/development versions.

Root cause

When curl_formadd_ccsid() encounters CURLFORM_CONTENTTYPE, it treats it as a separator and immediately converts any pending CURLFORM_COPYCONTENTS via Curl_formadd_convert() (line 897), then clears both the content and length indexes (lines 902-903). Because the explicit length has not been seen yet, Curl_formadd_convert() falls back to strlen(value) + 1 (line 675). For a NUL-leading binary body this produces a 1-byte allocation (line 690). The later CURLFORM_CONTENTLEN is still forwarded to core curl_formadd(), which copies the full declared length from that undersized buffer — a heap-buffer-overflow read.

There is also a secondary overread: the premature strlen() at line 675 reads beyond the caller's buffer if the binary content is not NUL-terminated.

Impact

The confirmed primitive is an out-of-bounds heap read whose contents are copied into the generated multipart request body. If that request crosses a trust boundary, adjacent heap data may be disclosed to the receiving server.

Constraints: the affected API is IBM i-specific and deprecated (curl_formadd is superseded by curl_mime). The trigger requires the application to supply binary content with the specific option ordering. I have not reproduced this natively on IBM i.

Reproduction

  1. Build an affected curl release, starting with 7.17.0, including the IBM i CCSID compatibility wrappers and with AddressSanitizer or an equivalent heap-bounds detector enabled.
  2. Write a small application using the deprecated curl_formadd_ccsid() API.
  3. Prepare binary form content with a truthful explicit length and an embedded NUL byte, preferably as the first byte so premature string-length calculation produces the smallest possible converted allocation.
  4. Add a form field name and then add the binary data with CURLFORM_COPYCONTENTS.
  5. Place CURLFORM_CONTENTTYPE after the binary content but before its corresponding CURLFORM_CONTENTLEN or CURLFORM_CONTENTSLENGTH.
  6. Place the truthful explicit content length after the content type and terminate the option list normally.
  7. Observe that encountering the content type causes the CCSID wrapper to convert the pending content before it has seen the explicit length.
  8. Confirm that the conversion path falls back to strlen(value) + 1; for NUL-leading data, this creates a one-byte converted allocation.
  9. Confirm that the later explicit length is still forwarded to the core curl_formadd() implementation.
  10. Serialize or submit the generated multipart form.
  11. Observe the vulnerable result: core form processing copies the full declared content length from the undersized converted allocation, and the memory checker reports a heap out-of-bounds read.
  12. If execution continues under a recovering memory checker, inspect the multipart body and confirm that bytes adjacent to the converted allocation can replace or follow the intended binary data.
  13. Repeat with bounded binary content that has no NUL terminator and confirm the secondary overread caused by the premature strlen() itself.
  14. As an ordering control, place the explicit content length before CURLFORM_CONTENTTYPE.
  15. Confirm that the control completes without a sanitizer error and preserves every supplied binary byte.
  16. As a second control, omit CURLFORM_CONTENTTYPE while retaining the explicit length and confirm correct serialization.
  17. If native IBM i instrumentation is unavailable, compile the production wrapper in a sanitizer-enabled environment with minimal platform declarations and use a same-CCSID conversion path so platform conversion stubs are not executed.
  18. Confirm a fix by deferring content conversion until its explicit length is known, preserving the pending content state across the content-type option, or rejecting the unsafe ordering.
  19. Repeat all three option orderings and verify that bounded binary data is processed exactly according to its explicit length without memory overreads.

Expected result

Form option order must not cause binary content to be treated as a NUL-terminated string. Once supplied, the explicit length must govern conversion and copying of the associated content.

Vulnerable result

CURLFORM_CONTENTTYPE triggers conversion before the later length is known, producing an undersized allocation. Core form processing subsequently trusts the explicit length and reads beyond that allocation into adjacent heap memory.

Suggested fix

Do not convert pending content at CURLFORM_CONTENTTYPE until the explicit length is known. Either defer conversion until end-of-parameter-list (where the length will have been seen), or preserve the content index across the CURLFORM_CONTENTTYPE separator when no length has been recorded yet.

Impact

An application using the IBM i curl_formadd_ccsid() wrapper with attacker-influenced binary form data may read beyond a heap allocation and include adjacent process memory in the generated multipart request. This could disclose sensitive heap contents to the receiving server or crash the process, although exploitation requires the deprecated platform-specific API and the vulnerable option ordering.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original