Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-59650

CVE-2026-59650: Bouncy Castle Java DH Agreement Vulnerability

CVE-2026-59650 is an MTI/A0 DH agreement flaw in Bouncy Castle for Java that exponentiates unvalidated peer values. This article covers the technical details, affected versions, security impact, and mitigation.

Published:

CVE-2026-59650 Overview

CVE-2026-59650 is an input validation flaw in the Bouncy Castle cryptographic library for Java. The MTI/A0 Diffie-Hellman (DH) key agreement implementation exponentiates a peer-supplied ephemeral value without validating it. An unvalidated peer public value can weaken the resulting shared secret and enable small subgroup or invalid-curve style attacks against static private keys. The issue affects Bouncy Castle for Java before version 1.85 and Bouncy Castle for Java LTS before version 2.73.12. The weakness is classified as [CWE-20] Improper Input Validation.

Critical Impact

A network attacker who can submit crafted DH public values to a party performing MTI/A0 agreement can compromise the confidentiality and integrity of derived keying material without authentication or user interaction.

Affected Products

  • Bouncy Castle for Java before 1.85
  • Bouncy Castle for Java LTS before 2.73.12
  • Applications embedding the org.bouncycastle.crypto.agreement.DHAgreement class

Discovery Timeline

  • 2026-08-03 - CVE-2026-59650 published to the National Vulnerability Database (NVD)
  • 2026-08-04 - Last updated in NVD database

Technical Details for CVE-2026-59650

Vulnerability Analysis

The DHAgreement class in Bouncy Castle implements the MTI/A0 authenticated Diffie-Hellman variant. In the vulnerable implementation, the peer's ephemeral public value message and the static public value pub are raised to the local private key without first checking that they lie in the correct subgroup or fall within the valid (1, p-1) range.

When an attacker supplies a public value that falls in a small subgroup of the multiplicative group modulo p, the resulting shared secret takes on only a limited set of values. This allows the attacker to recover bits of the static private exponent through repeated interactions, or to force predictable shared secrets that undermine confidentiality of subsequent traffic protected by the derived keys.

Root Cause

The calculateAgreement method accepted the peer parameters pub and message without performing null checks or full range validation on message. The prior code validated pub.getY() but did not apply the same subgroup and range constraints to the ephemeral message value that is also exponentiated with the local private key.

Attack Vector

An attacker who can act as a peer in an MTI/A0 exchange submits a maliciously chosen small-order or out-of-range integer as the ephemeral value. The victim exponentiates it with its private key and derives a predictable shared secret. Repeated queries against a static private key allow progressive key recovery, defeating the confidentiality of the agreement.

java
// Security patch in core/src/main/java/org/bouncycastle/crypto/agreement/DHAgreement.java
// Adds proper validation of peer ephemeral value in DHAgreement

     * calculate the next message in the agreement sequence. In this case
     * this will represent the shared secret.
     */
-    public BigInteger calculateAgreement(
-        DHPublicKeyParameters   pub,
-        BigInteger              message)
+    public BigInteger calculateAgreement(DHPublicKeyParameters pub, BigInteger message)
    {
+        if (pub == null)
+        {
+            throw new NullPointerException("'pub' cannot be null");
+        }
+        if (message == null)
+        {
+            throw new NullPointerException("'message' cannot be null");
+        }
+
        if (!pub.getParameters().equals(dhParams))
        {
            throw new IllegalArgumentException("Diffie-Hellman public key has wrong parameters.");
        }

        BigInteger p = dhParams.getP();

-        BigInteger peerY = pub.getY();
-        if (peerY == null || peerY.compareTo(ONE) <= 0 || peerY.compareTo(p.subtract(ONE)) >= 0)
-        {
-            throw new IllegalArgumentException("Diffie-Hellman public key is weak");
-        }
+        // Both peer-supplied values are raised to our (potentially static) private key, so both must

Source: Bouncy Castle patch commit daeaae9

Detection Methods for CVE-2026-59650

Indicators of Compromise

  • Repeated DH key agreement failures or successful sessions initiated from the same peer with anomalous public value distributions.
  • Java applications loading bcprov or bc-lts JAR files with versions earlier than 1.85 or 2.73.12.
  • Unexpected IllegalArgumentException traces originating from org.bouncycastle.crypto.agreement.DHAgreement after patching.

Detection Strategies

  • Inventory Java application dependencies using Software Composition Analysis (SCA) to flag vulnerable Bouncy Castle versions.
  • Instrument cryptographic code paths to log peer public values that fall outside (1, p-1) or belong to small subgroups.
  • Search build artifacts and container images for bcprov-jdk*.jar files matching pre-patch versions.

Monitoring Recommendations

  • Alert on inbound TLS or custom protocol handshakes that repeatedly present identical or degenerate DH public values.
  • Monitor process telemetry for Java services loading unpatched Bouncy Castle classes at runtime.
  • Track SBOMs across CI/CD pipelines to prevent reintroduction of vulnerable library versions.

How to Mitigate CVE-2026-59650

Immediate Actions Required

  • Upgrade Bouncy Castle for Java to version 1.85 or later.
  • Upgrade Bouncy Castle for Java LTS to version 2.73.12 or later.
  • Rotate any long-lived static DH keys that may have been exposed to untrusted peers using MTI/A0 agreement.

Patch Information

The fix is committed in the Bouncy Castle repository at commit daeaae9d7075d04f40812e68671ebf4c777b5148. The patch adds null checks and full-range validation for both pub and message inputs to DHAgreement.calculateAgreement, ensuring peer-supplied values are rejected before exponentiation. See the official CVE-2026-59650 wiki entry and the upstream patch commit for details.

Workarounds

  • Avoid using the MTI/A0 DH agreement primitive until the library is upgraded, favoring ECDH or authenticated protocols with validated parameters.
  • Enforce ephemeral-only DH keys so that a compromised session key does not expose a long-lived private exponent.
  • Validate peer public values in application code before invoking DHAgreement.calculateAgreement if immediate patching is not feasible.
bash
# Verify installed Bouncy Castle version in a project
mvn dependency:tree | grep -i bcprov

# Enforce a minimum patched version via Maven dependency management
# <dependency>
#   <groupId>org.bouncycastle</groupId>
#   <artifactId>bcprov-jdk18on</artifactId>
#   <version>1.85</version>
# </dependency>

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.