ExportXMLWordPrintableJSON

    • None
    • 0.1
    • Fully Compatible
    • Dotnet Drivers
    • Not Needed
    • None
    • None
    • None
    • None
    • None
    • None

      Summary

      A client presenting a keyless look-alike certificate silently rides another client's certificate-authenticated database connections, because certificates are compared by issuer and serial only.

      Impact

      A principal holding only public certificate metadata performs authenticated MongoDB reads and writes as another principal's X.509 identity, bypassing the server's proof-of-private-key client authentication.
      Severity: high (upper bound critical)
      Exploitability: likely_exploitable — The attacker fully controls their certificate's issuer and serial (public values copied from the victim) and their connection settings; the only conditions outside their control are co-residence with the victim's client in one process and knowledge of the victim's endpoints.
      Customer data: customer_content, customer_metadata (api_response)

      Location

      • src/MongoDB.Driver/SslSettings.cs:279 in X509CertificateCollectionEqualityComparer.Equals
      • src/MongoDB.Driver/SslSettings.cs:292 in X509CertificateCollectionEqualityComparer.GetHashCode
      • src/MongoDB.Driver/SslSettings.cs:190 in SslSettings.Equals
      • src/MongoDB.Driver/ClusterKey.cs:239 in ClusterKey.Equals
      • src/MongoDB.Driver/ClusterKey.cs:189 in ClusterKey.CalculateHashCode
      • src/MongoDB.Driver/ClusterRegistry.cs:192 in ClusterRegistry.GetOrCreateCluster
      • src/MongoDB.Driver/Core/Connections/SslStreamFactory.cs:60 in SslStreamFactory.CreateStream

      Reproduction / trigger path

      Analyzed trigger path from static analysis — not an executed PoC. Confirm with a concrete repro before handing off.

      Attacker controls: The attacker controls the certificate object their client supplies (issuer DN and serial number are freely mintable and copied from the victim's public certificate metadata) plus all connection settings needed to make the remaining ClusterKey fields match the victim's (servers, credential, defaults).

      1. (source) src/MongoDB.Driver/SslSettings.cs:71 in SslSettings.ClientCertificates (setter) — Attacker-influenced X509Certificate objects enter the driver via the only certificate ingress — the programmatic TLS settings property (no connection-string path exists).
      2. (hop) src/MongoDB.Driver/MongoClientSettings.cs:1335 in MongoClientSettings.ToClusterKey — The SslSettings (including the certificate collection) is embedded into the ClusterKey used for cluster-cache lookup.
      3. (hop) src/MongoDB.Driver/MongoClient.cs:92 in MongoClient (constructor) — Every MongoClient unconditionally resolves its cluster through the process-wide singleton registry (IClusterSource.cs:30 → ClusterRegistry.Instance).
      4. (hop) src/MongoDB.Driver/ClusterKey.cs:189 in ClusterKey.CalculateHashCode — The dictionary hash covers only credential and servers — certificate differences cannot break the hash-bucket match, so even byte-different forged certificates reach the Equals check.
      5. (hop) src/MongoDB.Driver/ClusterKey.cs:239 in ClusterKey.Equals — Key equality delegates the certificate comparison to SslSettings.Equals.
      6. (hop) src/MongoDB.Driver/SslSettings.cs:279 in X509CertificateCollectionEqualityComparer.Equals — SequenceEqual with default X509Certificate.Equals declares two certificates equal when issuer name and serial number match, ignoring the private key — credential-distinct settings compare identical.
      7. (hop) src/MongoDB.Driver/ClusterRegistry.cs:192 in ClusterRegistry.GetOrCreateCluster — On key match the existing cluster (built from the first client's settings, including its certificates at ClusterRegistry.cs:156) is returned to the second client.
      8. (sink) src/MongoDB.Driver/Core/Connections/SslStreamFactory.cs:60 in SslStreamFactory.CreateStream — TLS handshakes present the first client's certificate and private key (options built at line 128 from the first client's settings), so the second client's commands execute authenticated as the first client's X.509 identity.

      Root cause

      • src/MongoDB.Driver/SslSettings.cs:279 — client certificate collections are compared with SequenceEqual using default X509Certificate.Equals, which per .NET semantics compares only issuer name and serial number, ignoring the private key and all other certificate content; SslSettings.cs:190 wires this comparer into SslSettings.Equals.
      • src/MongoDB.Driver/ClusterKey.cs:239 — ClusterKey.Equals uses object.Equals on the SslSettings, inheriting the weak certificate equality; ClusterKey.cs:189-196 computes the dictionary hash from credential and servers only, so certificate differences never even break the hash lookup — a forged certificate with copied issuer/serial strings collides despite different raw bytes.
      • src/MongoDB.Driver/ClusterRegistry.cs:192 — GetOrCreateCluster (process-wide singleton, reached unconditionally from MongoClient.cs:92 via IClusterSource.cs:30) returns the existing cluster whenever keys compare equal, merging credential-distinct clients.
      • src/MongoDB.Driver/ClusterRegistry.cs:156 and src/MongoDB.Driver/Core/Connections/SslStreamFactory.cs:60/66/88/91/128 — the reused cluster's TLS streams authenticate with the FIRST client's certificate collection (and its private key), so the second client's commands execute under the first client's X.509 identity.

      Ownership

      Assigned teams: @mongodb/dbx-csharp-dotnet


      Filed from Aegis finding 563a539e7e36 (scan scan-4dd77e1a1432) · primitive: Cluster-cache key collision via issuer-and-serial-only certificate equality merges credential-distinct clients onto one pool authenticated with the first client's private key. · categories: Authentication Bypass, Cross-Tenant Access, Role Confusion

      https://docs.google.com/document/d/1osPjSiI-pvMXtrI49QVqwrIK21_nU38fsp7tJlQpDlY/edit?tab=t.0#heading=h.biijq6ke6z0p

            Assignee:
            Oleksandr Poliakov
            Reporter:
            Oleksandr Poliakov
            None
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: