PT-2026-42203 · Git · Tls

Published

2026-05-20

·

Updated

2026-05-20

·

CVE-2026-45389

CVSS v3.1

7.4

High

VectorAV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N
The TLS server implementation does not validate the KeyUsage and ExtendedKeyUsage extensions of client certificates when mutually authenticated TLS is requested. This can lead to impersonation with a certificate issued to a server.

Scenario

An operations engineer enables mTLS on the admin endpoint of a banking service. The setup is canonical: provide an authenticator on the ocaml-tls listener. She believes the gate is now set: only certificates issued under the corporate root, intended for client authentication, can authenticate at the admin endpoint.
An attacker inside the same corporate trust domain holds the legitimate TLS server cert for some internal HTTPS service they administer. The cert is real, signed by the corporate root, valid, not revoked. Its Extended Key Usage extension lists id-kp-serverAuth and nothing else — the cert was issued for serving HTTPS, not for authenticating clients. The X.509 RFC says exactly that distinction: a cert's role is constrained by its EKU, and a serverAuth-only cert is not authorised to act as a client.
The attacker presents that cert to the bank's ocaml-tls mTLS listener. The hook fires, the chain validates against the corporate root. The ocaml-tls library's does neither check that the presented certificate includes digitalSignature in its keyUsage, neither looks that clientAuth is present in the ExtendedKeyUsage. The handshake completes. The attacker is now authenticated as a client at the bank's admin endpoint, holding a cert the corporate CA never authorised for client identity. Every server cert under the same trust store is an mTLS client cert at this listener — with no further coordination, no compromise of the CA, and no compromise of any legitimate client.
The catastrophic deployment shape is the operator who puts Mozilla's public-PKI trust store on the mTLS-server side. There, every public TLS server certificate in the world — every Let's Encrypt cert, every DigiCert cert, anything an attacker can buy or freely issue for any domain they control — becomes an mTLS client cert at the listener, provided the application authorises identities by chain-validity alone rather than by post-validation CN/SAN gating. That branch reaches CVSS 9.1; the realistic dominant case is the corporate-internal-CA shape at 7.4.

Attack

Three actors: Operator (deploys ocaml-tls with mTLS for access control), Attacker (holds a CA-signed TLS server cert under a CA the operator's mTLS listener trusts), Server (the ocaml-tls listener serving the admin endpoint).
  Corporate CA (in ocaml-tls trust store; also issues the Operator's internal HTTPS server certs)
    │
    ├──▶ Operator's internal HTTPS service
    │   cert: EKU={serverAuth}, used legitimately as TLS server
    │
    └──▶ Attacker (admins one of those internal HTTPS services)
        cert: EKU={serverAuth} (legitimate)
        key: in attacker's possession (legitimately)

  Attacker presents own server cert as a client cert to:
  Operator's ocaml-tls mTLS listener → HTTP 200 OK
Sequence:
  1. Operator runs ocaml-tls with authenticator = Some X509.Authenticator.chain of trust <internal root CA>.
  2. Attacker initiates a TLS handshake with the listener, presenting their existing serverAuth-only leaf in the Certificate message.
  3. validateCerts (handshake server.ml) or answerClientCertificate (handshake server13.ml) call validateChain, which passes.
  4. CertificateVerify arrives, validates. Handshake completes.
  5. WAI delivers the HTTP request to the application. The application reads the cert subject (CN, SAN) and treats it as the authenticated client identity for downstream authorization, audit logging, session binding.
Attack properties:
  • The attacker needs a CA-signed leaf with EKU {serverAuth} only, chained to a CA the listener trusts for client auth. The realistic corporate-internal-CA case: the attacker holds a legitimate server cert under the same CA; AC:H. The catastrophic public-PKI-overlap case: any public CA-signed server cert; AC:L, score 9.1.
  • No private-key compromise of any legitimate client is required. No CA compromise. No collusion with the CA. The attacker uses their own legitimate cert in a role it was not issued for.
  • Out of scope: an attacker without a chain-valid cert at the listener's trust store. The CA-signed prerequisite is what holds AC above L in the dominant case.

Scope

Affected: any ocaml-tls deployment that
  • enables mTLS via authenticator = Some ..., AND
  • trusts a CA whose issuance policy permits or has permitted certs with EKU = {serverAuth} only — which is essentially every CA, since serverAuth-only is the dominant TLS server cert shape.
Realistic exposure shapes:
  • Corporate internal CA without strict client/server EKU separation. Any service holding a legitimate corporate-CA-issued TLS server cert can authenticate to any mTLS-gated API in the same trust domain. Service-mesh terminator → admin API; internal HTTPS service → internal mTLS microservice. The role boundary disappears within the trust domain. AC:H, CVSS 7.4.
  • Public-PKI trust-store reuse. The operator placed Mozilla's CA bundle (or any other public-web-PKI trust store) on the mTLS-server side. Every public TLS server cert in the world is now an mTLS client cert. AC:L, CVSS 9.1. Operator misconfiguration shape; uncommon but observed.
Not in scope:
  • Deployments where authenticator = None (no mTLS).
  • Deployments where the application authorises identity by post-validation CN/SAN gating that the attacker's serverAuth-only cert cannot satisfy. The TLS layer accepts the attacker, but the app rejects on the next gate. This narrows the exposure but does not remove it — any ocaml-tls consumer relying on the TLS layer alone for identity is exposed.
  • Deployments that already check KeyUsage/ExtendedKeyUsage after the handshake completed (rare).

Timeline

  • 2026-04-24: vulnerability discovered
  • 2026-05-09: vulnerability reported to the OCaml security team
  • 2026-05-10: patch prepared
  • 2026-05-14: patch approved by reporter
  • 2026-05-20: ocaml-tls 2.1.0 released, security advisory published

Fix

Related Identifiers

CVE-2026-45389
OSEC-2026-07

Affected Products

Tls