{"id":"OSEC-2026-30","summary":"Ephemeron data is freed while still referenced when the key is an `Infix_tag` closure","details":"## Summary\n\nIn OCaml before 4.14.5, when the key of an ephemeron is a closure with `Infix_tag` (a function of a mutually recursive group that is not the first function), the mark phase does not keep the ephemeron's data alive, although the key is alive. The clean phase does treat the key as alive, so it leaves the data field filled. The sweep phase then frees the data block. After a major collection the ephemeron's data field still points to the freed block.\n\nThis looks like the part of [#7810](https://github.com/ocaml/ocaml/issues/7810) that PR [#9742](https://github.com/ocaml/ocaml/pull/9742) did not cover. PR [#9742](https://github.com/ocaml/ocaml/pull/9742) fixed the clean phase and the minor collector. It did not change `mark_ephe_aux`.\n\nPlease note that the CVSS score high is under the conditions:\n- *if* the application is using ephemerons,\n- and *if* the application is available over the network,\n- and *if* the attacker can find a way to exploit the memory safety issue in an attack chain.\n\n## Reproduction\n\n```ocaml\n[@@@alert \"-old_ephemeron_api\"]\nlet infix n = let rec f () = n and g () = f () in g\n\nlet build key n =\n  let e = Ephemeron.K1.create () in\n  let w = Weak.create 1 in\n  let d = ref n in\n  Ephemeron.K1.set_key e key;\n  Ephemeron.K1.set_data e d;\n  Weak.set w 0 (Some d);\n  (e, w)\n\nlet run key =\n  let (e, w) = build key 1 in\n  Gc.full_major ();\n  Printf.printf \"tag=%d weak=%b check_key=%b check_data=%b\\n\"\n    (Obj.tag (Obj.repr key)) (Weak.check w 0)\n    (Ephemeron.K1.check_key e) (Ephemeron.K1.check_data e);\n  ignore (Sys.opaque_identity key)\n\nlet () =\n  if Sys.argv.(1) = \"infix\" then run (infix 1) else run (ref 1)\n```\n\n`Obj` is used only to print the tag of the key. The program does not read the\ndata after the collection.\n\n## Timeline\n\n- 2026-10-04: initial report via email\n- 2026-10-09: develop and committed the fix\n- 2026-11-03: fix was reviewed and merged\n- 2026-11-06: OCaml 4.14.5 released","modified":"2026-11-06T13:45:02.509895083Z","published":"2026-11-06T12:30:00Z","database_specific":{"osv":"https://github.com/ocaml/security-advisories/tree/generated-osv/2026/OSEC-2026-30.json","human_link":"https://github.com/ocaml/security-advisories/tree/main/advisories/2026/OSEC-2026-30.md","cwe":["CWE-416"]},"affected":[{"package":{"name":"ocaml","ecosystem":"opam","purl":"pkg:opam/ocaml"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"4.14.5"}]}],"versions":["3.07","3.07+1","3.07+2","3.08.0","3.08.1","3.08.2","3.08.3","3.08.4","3.09.0","3.09.1","3.09.2","3.09.3","3.10.0","3.10.1","3.10.2","3.11.0","3.11.1","3.11.2","3.12.0","3.12.1","4.00.0","4.00.1","4.01.0","4.02.0","4.02.1","4.02.2","4.02.3","4.02.4","4.03.0","4.03.1","4.04.0","4.04.1","4.04.2","4.04.3","4.05.0","4.05.1","4.06.0","4.06.1","4.06.2","4.07.0","4.07.1","4.07.2","4.08.0","4.08.1","4.08.2","4.09.0","4.09.1","4.09.2","4.10.0","4.10.1","4.10.2","4.10.3","4.11.0","4.11.1","4.11.2","4.11.3","4.12.0","4.12.1","4.12.2","4.13.0","4.13.1","4.13.2","4.14.0","4.14.1","4.14.2","4.14.3","4.14.4"],"ecosystem_specific":{"opam_constraint":"ocaml {\u003c \"4.14.5\"}"},"database_specific":{"source":"https://github.com/ocaml/security-advisories/blob/generated-osv/2026/OSEC-2026-30.json"}},{"ranges":[{"type":"GIT","repo":"https://github.com/ocaml/ocaml","events":[{"introduced":"0"},{"fixed":"da301a20833b765e268d677fe693d29fe51793ad"}]}],"versions":["4.14.4","4.14.3","4.14.2","4.14.2-rc1","4.14.1-rc1","4.14.1","4.14.0","4.14.0-rc2","4.14.0-rc1","4.14.0-beta1","4.14.0-alpha2","4.14.0-alpha1","flambda_fork_point"],"database_specific":{"source":"https://github.com/ocaml/security-advisories/blob/generated-osv/2026/OSEC-2026-30.json"}}],"schema_version":"1.9.2","severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:L/VA:H/SC:N/SI:N/SA:N/E:P"}],"credits":[{"name":"Igor Santos-Grueiro","type":"REPORTER"},{"name":"Hannes Mehnert","type":"COORDINATOR"},{"name":"Florian Angeletti","type":"REMEDIATION_REVIEWER"},{"name":"Gabriel Scherer","type":"REMEDIATION_DEVELOPER"}]}