Dear all,
cohttp 6.3.0 is released onto opam-repository with some important security fixes (OSEC-2026-16):
-
cohttp:
Cohttp.Path.resolve_local_fileno longer escapes the docroot when
given percent-encoded traversal sequences such as..%2f..%2f. The URI path
is percent-decoded exactly once before.and..segments are removed.
(#1145 @avsm and Sapphire Livingstone, review by @mdales @edwintorok @patricoferris) -
cohttp:
Cohttp.Path.resolve_local_filecollapses empty path segments and
drops a trailing slash. A request for/dir//sub/now resolves to
docroot/dir/subinstead ofdocroot/dir//sub/. (#1145 @avsm) -
cohttp: Add
Cohttp.Path.normalise, which converts a request URI into a
relative path that cannot ascend above its root. Servers that make access
control decisions on path segments must apply it toRequest.uribefore
inspecting them, asRequest.uridoes not normalise absolute-form or
percent-encoded targets. (#1145 @avsm)let callback _conn req _body = let uri = Cohttp.Request.uri req in match String.split_on_char '/' (Cohttp.Path.normalise uri) with | "admin" :: _ when not (authorised req) -> Server.respond_not_found () | _ -> let fname = Cohttp.Path.resolve_local_file ~docroot ~uri in Server.respond_file ~fname ()Normalisation is not applied by default, as existing code may depend on the
present semantics, which are safe when not combined with local file
resolution. -
cohttp-mirage: The static file server normalises the request path of every
request, including directory requests, before looking it up in the mirage-kv
store. Keys are now percent-decoded, so/my%20file.txtretrieves the key
my file.txtrather thanmy%20file.txt(#1145 @avsm, review by @mdales @edwintorok) -
cohttp-mirage: The
request_fncallback receives the request URI unchanged.
A request that falls back to an index page previously received a URI
rewritten to that page. (#1145 @avsm) -
cohttp: do not add
Transfer-Encoding/Content-Lengthframing headers to
responses that cannot have a body (1xx, 204 and 304). This fixes WebSocket
handshakes. (@mefyl @avsm, #1141) -
http: add
Status.body_allowed, the response-status counterpart to the
existingMethod.body_allowed, for users constructing responses by hand
(#1141)
Please upgrade as soon as possible, and note the new normalise function for your own HTTP path splitting needs.
Thank you to everyone who helped with handling the security issue, and especially Sapphire Livingstone for the discovery, report and guidance with the fix:
- Sapphire Livingstone - REPORTER
- Sapphire Livingstone - REMEDIATION_DEVELOPER
- Anil Madhavapeddy - REMEDIATION_DEVELOPER
- Anil Madhavapeddy - REMEDIATION_REVIEWER
- Michael Dales - REMEDIATION_REVIEWER
- Edwin Torok - REMEDIATION_REVIEWER
- Patrick Ferris - REMEDIATION_REVIEWER
- Hannes Mehnert - COORDINATOR