GET /conferences/ocaml/<path> on ocaml.org concatenates the raw request target onto OCAMLORG_V2_PATH (/v2) and serves it with Dream.from_filesystem, bypassing the path validation that Dream.static performs. An unauthenticated request containing .. segments escapes /v2 and reads arbitrary files as the server process, which runs as root in the container.
Please note that the live deployment of https://ocaml.org is in a dedicated Docker container which does not contain any secrets. Thus the vulnerability is in the ocaml.org source code, but there has been no impact for the live deployment.
src/ocamlorg_web/lib/handler.ml:1544 (commit ocaml/ocaml.org@31249f2d69fcb243284d3a6a2b91c0a4963f25b5):
let v2_asset req =
let</>? path =
try Some (Config.v2_path ^ Dream.target req) with _ -> None
in
let</>? () = if Sys.file_exists path then Some () else None in
Filename.(Dream.from_filesystem (dirname path) (basename path) req)
The route is public (src/ocamlorg_web/lib/router.ml:186):
Dream.get "/conferences/ocaml/**" Handler.v2_asset;
Config.v2_path is OCAMLORG_V2_PATH, set to /v2 in the production image (Dockerfile:68). Dream.target is the request target as received; nothing rejects . or .. components.
{
"cwe": [
"CWE-22"
],
"human_link": "https://github.com/ocaml/security-advisories/tree/main/advisories/2026/OSEC-2026-28.md",
"osv": "https://github.com/ocaml/security-advisories/tree/generated-osv/2026/OSEC-2026-28.json"
}