Skip to content

fix: reject invalid multipart MIME header controls - #105

Merged
jbeckwith-oai merged 1 commit into
mainfrom
codex/harden-multipart-mime-headers
Aug 19, 2026
Merged

jbeckwith-oai merged 1 commit into
mainfrom
codex/harden-multipart-mime-headers

Conversation

@jbeckwith-oai

Copy link
Copy Markdown
Contributor

Summary

  • Reject invalid MIME-header control bytes in multipart field names, uploaded filenames, and content types before constructing multipart headers.
  • Preserve valid Unicode, quotes, backslashes, horizontal tabs, supported public APIs, streaming, retry, content-length, and cancellation behavior.
  • Add exhaustive encoder and CLI regression coverage, including nested JSON/YAML keys, every prohibited ASCII control byte, both filename interfaces, reader cleanup, unknown-length streams, and real newline-containing Unix filenames.

Validation

  • GOCACHE=/Users/jbeckwith/.cache/openai-cli-go-build ./scripts/test -skip '^TestFilesCreateCLICancelClosesStalledFIFO$' — all repository packages passed; Windows/amd64 tests compiled successfully.
  • GOCACHE=/Users/jbeckwith/.cache/openai-cli-go-build go test -race ./internal/apiform ./pkg/cmd -run '^(TestEncode|TestMarshal|TestMultipart|TestFilesCreateCLIRejectsNewlineFilenameBeforeRequest|TestFilesCreateCLIStreams|TestFilesCreateCLIDoesNotReplayUploads|TestImagesEditCLI|TestExactLength|TestOpenFileUpload|TestEmbedFiles)' -count=1
  • GOCACHE=/Users/jbeckwith/.cache/openai-cli-go-build go vet ./...
  • GOCACHE=/Users/jbeckwith/.cache/openai-cli-go-build ./scripts/lint
  • GOCACHE=/Users/jbeckwith/.cache/openai-cli-go-build GOOS=linux GOARCH=amd64 go build ./...

TestFilesCreateCLICancelClosesStalledFIFO was excluded locally because its macOS EPIPE assertion also fails unchanged at the original base revision; Linux CI will run the complete unfiltered suite.

Copilot AI lite review requested due to automatic review settings August 19, 2026 18:20

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens multipart form encoding in the CLI and internal apiform encoder by rejecting ASCII control bytes that can be used for MIME header injection (e.g., CR/LF) in multipart field names, uploaded filenames, and content types.

Changes:

  • Add control-byte validation for multipart field names, filenames, and content types before constructing part headers.
  • Add exhaustive security/regression tests for apiform multipart encoding, including nested decoded JSON/YAML keys and all prohibited ASCII control bytes.
  • Add CLI-level regression tests ensuring invalid multipart header inputs are rejected before reading upload streams and before issuing HTTP requests.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
pkg/cmd/multipartheader_test.go Adds CLI/multipart streaming tests to ensure invalid header controls are rejected early (no upload reads, owned readers closed, no requests sent).
internal/apiform/encoder.go Introduces control-byte validation for multipart header-relevant values (field name, filename, content type) before part header construction.
internal/apiform/encoder_security_test.go Adds comprehensive encoder security coverage for control-byte rejection and preservation of valid Unicode/escaping/tab behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@jbeckwith-oai
jbeckwith-oai marked this pull request as ready for review August 19, 2026 18:25
@jbeckwith-oai
jbeckwith-oai requested a review from a team as a code owner August 19, 2026 18:25

@HAYDEN-OAI HAYDEN-OAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Independent deep security review at 0b79621 found no introduced P1/P2 issues.

@jbeckwith-oai
jbeckwith-oai added this pull request to the merge queue Aug 19, 2026
Merged via the queue into main with commit fad98b4 Aug 19, 2026
9 checks passed
@jbeckwith-oai
jbeckwith-oai deleted the codex/harden-multipart-mime-headers branch August 19, 2026 18:47
@openai-sdks openai-sdks Bot mentioned this pull request Aug 19, 2026
markstuart-oai pushed a commit to fallintoplace/openai-cli that referenced this pull request Sep 6, 2026
Automated Release PR
---


## [1.9.0](openai/openai-cli@v1.8.0...v1.9.0)
(2026-08-26)


### Features

* **api:** Add residency flag and deprecate geography
([openai#136](openai#136))
([e460582](openai@e460582))


### Bug Fixes

* Add provenance-aware untrusted stdin mode
([openai#137](openai#137))
([a133707](openai@a133707))
* build CLI releases with patched Go toolchains
([openai#93](openai#93))
([a58f1cc](openai@a58f1cc))
* discard fish completion diagnostics
([openai#109](openai#109))
([4f35fc0](openai@4f35fc0))
* escape raw output controls on interactive terminals
([openai#112](openai#112))
([7601afb](openai@7601afb))
* fail closed when bootstrapping Go dependencies
([openai#94](openai#94))
([4ebe610](openai@4ebe610))
* lock and verify Steady mock tooling
([openai#95](openai#95))
([681d595](openai@681d595))
* prepare release artifacts before publishing
([openai#111](openai#111))
([4193619](openai@4193619))
* redact sensitive response headers in debug logs
([openai#106](openai#106))
([4931572](openai@4931572))
* reject invalid multipart MIME header controls
([openai#105](openai#105))
([fad98b4](openai@fad98b4))
* restrict downloaded file permissions
([openai#107](openai#107))
([7a3a7d1](openai@7a3a7d1))
* safely construct bash file completions
([openai#110](openai#110))
([b3e0946](openai@b3e0946))
* stream binary download responses
([openai#108](openai#108))
([1f3ba6c](openai@1f3ba6c))
* stream multipart uploads without buffering
([openai#65](openai#65))
([bcf0ecd](openai@bcf0ecd))
* verify GoReleaser before privileged release execution
([openai#96](openai#96))
([b3729ea](openai@b3729ea))


### Chores

* **api:** clarify image background and audio delta docs
([openai#124](openai#124))
([056f306](openai@056f306))
* **api:** No customer-visible SDK or public API changes
([openai#128](openai#128))
([12e0d28](openai@12e0d28))
* **api:** refresh image model API reference
([openai#115](openai#115))
([a771913](openai@a771913))
* **api:** Refresh the bundled OpenAPI reference
([openai#66](openai#66))
([d14387a](openai@d14387a))
* **api:** Report no customer-visible SDK or public API changes
([openai#113](openai#113))
([8da2d53](openai@8da2d53))
* **api:** update generation metadata only
([openai#138](openai#138))
([4244a62](openai@4244a62))
* configure Dependabot for Go and GitHub Actions
([openai#69](openai#69))
([f495366](openai@f495366))
* **deps:** bump actions/attest-build-provenance from 4.1.0 to 4.2.2
([openai#102](openai#102))
([6594c73](openai@6594c73))
* **deps:** bump actions/checkout from 6.0.2 to 7.0.1
([openai#103](openai#103))
([ce6a6d0](openai@ce6a6d0))
* **deps:** bump actions/checkout from 6.0.2 to 7.0.1
([openai#134](openai#134))
([f40d5f2](openai@f40d5f2))
* **deps:** bump actions/download-artifact from 4.3.0 to 8.0.1
([openai#133](openai#133))
([98ed029](openai@98ed029))
* **deps:** bump actions/github-script from 7.1.0 to 9.0.0
([openai#132](openai#132))
([978ce47](openai@978ce47))
* **deps:** bump actions/setup-go in /
([openai#101](openai#101))
([5564982](openai@5564982))
* **deps:** bump actions/upload-artifact from 4.6.2 to 7.0.1
([openai#104](openai#104))
([b3ac15a](openai@b3ac15a))
* **deps:** bump github.com/charmbracelet/bubbles from 0.21.0 to 1.0.0
([openai#99](openai#99))
([7ac7035](openai@7ac7035))
* **deps:** bump github.com/urfave/cli/v3 from 3.4.1 to 3.10.1 in the
go-minor-and-patch group across 1 directory
([openai#130](openai#130))
([ddc612e](openai@ddc612e))
* **deps:** bump the charmbracelet group across 1 directory with 2
updates ([openai#97](openai#97))
([2137b80](openai@2137b80))
* **deps:** bump the codeql group across 1 directory with 2 updates
([openai#100](openai#100))
([c95ac0a](openai@c95ac0a))
* **deps:** bump the codeql group across 1 directory with 2 updates
([openai#131](openai#131))
([58e3bdd](openai@58e3bdd))
* **deps:** bump the go-minor-and-patch group across 1 directory with 5
updates ([openai#98](openai#98))
([74822be](openai@74822be))
* **deps:** update openai-go to v3.51.0
([openai#63](openai#63))
([68e3e70](openai@68e3e70))
* **deps:** update openai-go to v3.52.0
([openai#67](openai#67))
([7d87ee2](openai@7d87ee2))
* set a 1,000-line custom-code budget
([openai#126](openai#126))
([016bfb2](openai@016bfb2))


### Documentation

* add secure CLI agent and contributor guidance
([openai#72](openai#72))
([09ec087](openai@09ec087))
* standardize CLI vulnerability disclosure policy
([openai#71](openai#71))
([d082a01](openai@d082a01))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: openai-sdks[bot] <284451331+openai-sdks[bot]@users.noreply.github.com>
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.

3 participants