CVE-2026-39414: Oversized S3 Select Records and a SIMD Bypass
Status: Released; the second-round fix was completed in June
Initial fix release: RELEASE.2026-04-17T00-00-00Z
Complete fix release: RELEASE.2026-06-18T00-00-00Z
GitHub issue: pgsty/minio#25
The first fix in April reused the existing 1 MiB maxCharsPerRecord limit for both CSV and ordinary JSON Lines. This prevented unbounded buffering while waiting for a delimiter and returned the explicit OverMaxRecordSize error to clients. A June review then found that CPUs with SIMD support took a different simdjson fast path that bypassed the limit completely.
The final solution sent JSON Lines through the bounded reader on every CPU. The same review also corrected error mapping, parser errors, and the flush of completed records before a terminal error. SILO temporarily gave up the SIMD fast path in exchange for consistent security semantics.
Threat model
An attacker can submit or query an object containing an extremely long single record. The reader continues buffering until it sees a record delimiter, allowing memory and CPU denial of service. More subtly, the same input can select a different implementation according to the machine’s CPU features. Safe behavior on a test machine does not necessarily prove safe behavior in production.
Error semantics are part of the fix. If an oversized record appears only as a generic InternalError, clients and monitoring systems cannot distinguish an enforced security limit from a server failure.
First round: reuse the existing 1 MiB invariant
The first patch did not invent a new configuration knob. It applied the existing maxCharsPerRecord = 1 MiB rule:
- the CSV splitter and line-delimited JSON rejected oversized records before buffering or parsing them further;
- the earliest splitter error was preserved instead of being overwritten by a partial decode;
- the error propagated as
OverMaxRecordSizerather than collapsing intoInternalError.
This was a deliberate compatibility contraction. Clients with lines or records larger than 1 MiB now had to split their input.
Second round: a hardware-dependent bypass
Following the call chain again in June exposed this path:
JSON Lines -> simdj.NewReader -> simdjson.ParseNDStream
When simdjson.SupportedCPU() returned true, JSON Lines bypassed the bounded json.PReader. The third-party parser kept reading past a chunk boundary until it found a newline. A generic reader wrapper could not simultaneously preserve already completed records and guarantee a bound on the next record.
The final choice was not another wrapper. JSON Lines temporarily stopped using the SIMD path and always used the bounded PReader. If SIMD support returns, that implementation must enforce the same record limit itself and pass the same CPU-independent regression suite.
Stream semantics corrected in the same round
The review also fixed several adjacent behaviors:
- use
errors.Asto pass through errors implementingSelectError, not just one concrete type; - have the JSON worker wrap parser failures as
JSONParsingError; - flush completed records still waiting below the batch threshold before emitting a terminal error event;
- preserve error priority in input order instead of letting a later oversized record overwrite an earlier parse error.
Those details determine whether a client sees the correct failure or a resource-limit fix that quietly broke the streaming protocol.
Deliberately left outside this CVE
- The historical mismatch between CSV
AllowQuotedRecordDelimiterand the outer physical-newline splitter. - Whether
\rin CRLF counts toward the record length. - Restoring SIMD performance without an equivalent bound.
These questions may be real, but they require independent AWS-compatibility evidence or a more complex quote-aware splitter. They did not belong in a security patch based on guesses.
Verification and release
The historical record includes oversized JSON Lines, error-code preservation, and behavior tests that do not depend on the local machine’s SIMD capabilities. go test ./internal/s3select/... -count=1 and git diff --check were recorded as passing.
The initial public fix was c5765dc; the complete June correction is fd69c89. Those tests were not rerun while preparing this article.
Final trade-offs
- JSON Lines performance may decrease; this incident did not produce a benchmark that quantifies it.
- The 1 MiB per-record limit rejects oversized input accepted by previous releases.
- Quoted, multiline CSV semantics still need separate work.
- Any future CPU-specific fast path must share the slow path’s security tests.
The second fix leaves the central lesson: a security invariant must hold across hardware-dependent paths. A green test on one CPU does not prove that another execution engine is protected.