CVE-2026-92390: -J no-clobber guarantee bypassed with 103 early hints
What the report claims
A server can bypass curl's -J no-clobber guarantee by sending a 103 Early Hints response before the final response, causing the output file to be truncated before curl checks for overwriting.
Compare with curl's recorded outcome
Known vulnerability
A real vulnerability: CVE-2026-92390 -J no-clobber guarantee bypassed with 103 early hints
Shown for comparison after analysis. The pipeline did not see this label.
ProveIt's finding
The available evidence does not settle the report. A maintainer should investigate.
Why this finding?
- The provided curl source code (lib/urldata.h lines 78-162) does not contain the relevant logic for -J, -i, Content-Disposition, Early Hints (103), or file opening/clobber handling. All claims are not_verifiable against the given code.
- The deterministic checks only confirm symbol existence (ETag, Location, control, honor_cd_filename) but do not show their usage.
- The RFC 8297 excerpt confirms the external requirement that 103 Early Hints must not affect final-response processing, which aligns with the report's argument.
- Without the actual header processing and file handling code (likely in lib/http.c, tool_operate.c, or similar), the claims cannot be confirmed or contradicted.
What still needs checking
- Source code for HTTP response header processing (especially informational/1xx responses)
- Source code for Content-Disposition parsing and -J filename handling
- Source code for -i/--include header display and output file opening logic
- Source code for --etag-save ETag handling
- The honor_cd_filename flag usage and where the no-clobber (O_EXCL) open occurs
How this analysis ran 5 claims · 0 citations verified
Checked against curl master on 2026-09-12 (04bfe8fbbf55). Dev evaluation split. Citation verification checks that a referenced line was in the evidence; it does not prove the model interpreted it correctly.
Review a draft reply to the reporter
Edit and verify before sending.
Thank you for the detailed report. The provided code snippet (lib/urldata.h) does not contain the HTTP header processing, Content-Disposition handling, or file opening logic needed to verify the claims. Could you point to the specific files/functions where: (1) 103 Early Hints responses are handled, (2) -i header display opens the output file, (3) Content-Disposition filename is parsed and the -J no-clobber check occurs, and (4) honor_cd_filename is set/checked? With those locations I can assess whether the early open bypasses the O_EXCL protection.
Inspect all claims and source code 5 claims · 1 code excerpts
Report claims
The no-clobber guarantee of -J is bypassed when a 103 Early Hints response opens the output file before Content-Disposition parsing
Read the reasoning
The provided source code (lib/urldata.h lines 78-162) only defines CURLcode typedefs and some structs. It does not contain the header processing logic, file opening logic, Content-Disposition handling, Early Hints (103) handling, or the -J/-i option implementations that would decide this claim. The code_refs 'CURLcode CURLMSG_DONE' and 'CURLcode CURLMSG_HEADER' appear to be message type constants, not the actual handling functions.
The issue occurs in the header display path for informational responses and --etag-save handling
Read the reasoning
Same as C1: the provided source does not contain the header display path, informational response handling, or --etag-save handling code. The location of the flaw cannot be verified from the given code.
Sending a 103 Early Hints response before the final response with a Content-Disposition filename matching the URL basename
Read the reasoning
The trigger mechanism (103 Early Hints causing early file open) depends on HTTP response handling code not present in the provided source snippet.
The pre-existing file is truncated and overwritten despite -J's documented protection
Read the reasoning
The impact claim (pre-existing file truncated despite -J protection) depends on the file opening logic and -J's O_EXCL check, which are not in the provided source.
Run curl -O -J -i against a server that sends 103 Early Hints first, causing the file to be truncated
Read the reasoning
The reproduction steps depend on the full curl command-line tool behavior, which cannot be verified from the single header file provided.
What the report says about other projects
confirmed Early Hints must not affect final-response processing
“Aside from performance optimizations, such evaluation of the 103 (Early Hints) response's header fields MUST NOT affect how the final response is processed.” source
Read the original report (excerpt)
Source code
| 78 | typedef CURLcode (Curl_send)(struct Curl_easy *data, /* transfer */ |
| 79 | int8_t sockindex, /* socketindex */ |
| 80 | const uint8_t *buf, /* data to write */ |
| 81 | size_t len, /* amount to send */ |
| 82 | bool eos, /* last chunk */ |
| 83 | size_t *pnwritten); /* how much sent */ |
| 84 | |
| 85 | /* On error return, the value of `pnread` has no meaning */ |
| 86 | typedef CURLcode (Curl_recv)(struct Curl_easy *data, /* transfer */ |
| 87 | int8_t sockindex, /* socketindex */ |
| 88 | char *buf, /* store data here */ |
| 89 | size_t len, /* max amount to read */ |
| 90 | size_t *pnread); /* how much received */ |
| 91 | |
| 92 | #include "mime.h" |
| 93 | #include "protocol.h" |
| 94 | #include "ftp.h" |
| 95 | #include "http.h" |
| 96 | #include "smb.h" |
| 97 | #include "mqtt.h" |
| 98 | #include "ftplistparser.h" |
| 99 | #include "multihandle.h" |
| 100 | #include "cf-socket.h" |
| 101 | |
| 102 | #ifdef HAVE_GSSAPI |
| 103 | # ifdef HAVE_GSSAPPLE |
| 104 | # include <GSS/gssapi.h> |
| 105 | # include <GSS/gssapi_oid.h> |
| 106 | # elif defined(HAVE_GSSGNU) |
| 107 | # include <gss.h> |
| 108 | # elif defined(HAVE_GSSAPI_H) |
| 109 | # include <gssapi.h> |
| 110 | # else /* MIT Kerberos */ |
| 111 | # include <gssapi/gssapi.h> |
| 112 | # include <gssapi/gssapi_krb5.h> /* for GSS_C_CHANNEL_BOUND_FLAG in 1.19+ */ |
| 113 | # endif |
| 114 | #endif |
| 115 | |
| 116 | #ifdef USE_LIBSSH2 |
| 117 | #include <libssh2.h> |
| 118 | #include <libssh2_sftp.h> |
| 119 | #endif /* USE_LIBSSH2 */ |
| 120 | |
| 121 | #define READBUFFER_SIZE CURL_MAX_WRITE_SIZE |
| 122 | #define READBUFFER_MAX CURL_MAX_READ_SIZE |
| 123 | #define READBUFFER_MIN 1024 |
| 124 | |
| 125 | /* The default upload buffer size, should not be smaller than |
| 126 | CURL_MAX_WRITE_SIZE, as it needs to hold a full buffer as could be sent in |
| 127 | a write callback. |
| 128 | |
| 129 | The size was 16KB for many years but was bumped to 64KB because it makes |
| 130 | libcurl able to do significantly faster uploads in some circumstances. Even |
| 131 | larger buffers can help further, but this is deemed a fair memory/speed |
| 132 | compromise. */ |
| 133 | #define UPLOADBUFFER_DEFAULT 65536 |
| 134 | #define UPLOADBUFFER_MAX (2 * 1024 * 1024) |
| 135 | #define UPLOADBUFFER_MIN CURL_MAX_WRITE_SIZE |
| 136 | |
| 137 | #ifdef USE_WINDOWS_SSPI |
| 138 | #include "curl_sspi.h" |
| 139 | #endif |
| 140 | |
| 141 | #ifndef CURL_DISABLE_DIGEST_AUTH |
| 142 | /* Struct used for Digest challenge-response authentication */ |
| 143 | struct digestdata { |
| 144 | struct Curl_creds *creds; |
| 145 | struct Curl_peer *origin; |
| 146 | #ifdef USE_WINDOWS_SSPI |
| 147 | BYTE *input_token; |
| 148 | size_t input_token_len; |
| 149 | CtxtHandle *http_context; |
| 150 | #else |
| 151 | char *nonce; |
| 152 | char *cnonce; |
| 153 | char *realm; |
| 154 | char *opaque; |
| 155 | char *qop; |
| 156 | char *algorithm; |
| 157 | int nc; /* nonce count */ |
| 158 | uint8_t algo; |
| 159 | BIT(stale); /* set true for re-negotiation */ |
| 160 | BIT(userhash); |
| 161 | #endif |
| 162 | }; |