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

CVE-2026-14682: Bouncy Castle Java DOS Vulnerability

CVE-2026-14682 is a denial of service flaw in Bouncy Castle for Java caused by unbounded memory allocation. Attackers can trigger out-of-memory conditions. This article covers technical details, affected versions, and mitigation.

Published:

CVE-2026-14682 Overview

CVE-2026-14682 is a denial-of-service vulnerability in Bouncy Castle for Java. The flaw resides in the ASN.1 definite-length parser, which allocates a heap buffer sized by an attacker-controlled length field before reading any payload bytes. A short, crafted input carrying a large declared length can drive an out-of-memory (OOM) condition in the parsing JVM. The issue is classified as [CWE-789] Memory Allocation with Excessive Size Value. It affects Bouncy Castle for Java, Bouncy Castle for Java LTS, and Bouncy Castle for Java FIPS (BC-FJA) across multiple release streams.

Critical Impact

A remote, unauthenticated attacker can trigger unbounded memory allocation by sending a crafted ASN.1 structure, exhausting heap and causing denial of service in any service that parses untrusted ASN.1, X.509, CMS, or PKCS input.

Affected Products

  • Bouncy Castle for Java before 1.85
  • Bouncy Castle for Java LTS before 2.73.12
  • Bouncy Castle for Java FIPS (BC-FJA) before bc-fips 1.0.2.7 (1.0.X), 2.0.2 (2.0.X), 2.1.3 (2.1.X), and before bctls-fips 1.0.24

Discovery Timeline

  • 2026-08-03 - CVE-2026-14682 published to NVD
  • 2026-08-04 - Last updated in NVD database

Technical Details for CVE-2026-14682

Vulnerability Analysis

Bouncy Castle's ASN.1 parser reads a definite-length header and then allocates a byte array matching that declared length in advance of consuming any content. When the declared length is large but the actual stream is short, the JVM commits a heap-sized allocation before the truncation is detected. Processes exposed to attacker-supplied encoded blobs, TLS handshakes, certificate chains, CMS/PKCS7 messages, or S/MIME payloads can be forced into OutOfMemoryError states. The vulnerability affects confidentiality and integrity as No, but availability impact is High.

Root Cause

The root cause is eager, unbounded up-front allocation in DefiniteLengthInputStream.toByteArray(). The parser trusted the DEF length prefix and executed new byte[(int)_remaining] before validating that data actually followed. The general-purpose helper Streams.readAll used a similar strategy, allocating new byte[len] before reading. Both allocators bypassed input-driven growth, so a hostile length prefix mapped directly to a large JVM heap request.

Attack Vector

Exploitation is network-reachable and requires no authentication or user interaction. An attacker sends a crafted ASN.1 message with a large declared definite length and minimal or no trailing bytes. Any Java service using vulnerable Bouncy Castle to parse the input, TLS peers, certificate validators, signature verifiers, key stores, will attempt the allocation and can be knocked offline.

The upstream fix replaces eager allocation with incremental buffer growth:

java
         StreamUtil.checkLength(_remaining, (long)getLimit());
 
-        byte[] bytes = new byte[(int)_remaining];
-        if ((_remaining -= Streams.readFully(_in, bytes, 0, bytes.length)) != 0)
-        {
-            throw new EOFException("DEF length " + _originalLength + " object truncated by " + _remaining);
-        }
-        setParentEofDetect(true);
-        return bytes;
+        // Read through this stream (not _in) so Streams.readLenBytesFully grows the buffer as bytes
+        // arrive - avoiding the eager new byte[_remaining] that let a short crafted header drive a
+        // heap-sized allocation before any data was read (CWE-789) - while read(byte[], int, int)
+        // above keeps the _remaining / parent-EOF bookkeeping and reports a truncated stream with the
+        // established "DEF length ... object truncated by ..." EOFException.
+        return Streams.readLenBytesFully(this, (int)_remaining);
     }
 }

Source: Bouncy Castle patch commit 37094e5

The corresponding helper in Streams.java now starts with a bounded buffer and doubles capacity as bytes arrive:

java
             throw new IllegalArgumentException("len cannot be negative");
         }
 
-        int chunkSize = Math.min(len, BUFFER_SIZE);
-        ByteArrayOutputStream buf = new ByteArrayOutputStream(chunkSize);
-        byte[] chunk = new byte[chunkSize];
-
-        int remaining = len;
-        while (remaining > 0)
+        // Start with a bounded buffer and grow it towards len (doubling) as bytes actually arrive,
+        // reading straight into the result rather than allocating new byte[len] up front. A hostile
+        // len therefore cannot drive a large allocation from a short input, and a small len still
+        // allocates its exact size once.
+        byte[] bytes = new byte[Math.min(len, BUFFER_SIZE)];
+        int count = 0;
+        while (count < len)
         {
-            int numRead = inStr.read(chunk, 0, Math.min(remaining, chunk.length));
+            if (count == bytes.length)
+            {
+                int expandedLength = (int)Math.min((long)len, 8L * bytes.length);
+                byte[] expanded = new byte[expandedLength];
+                System.arraycopy(bytes, 0, expanded, 0, count);
+                bytes = expanded;
+            }
+
+            int numRead = inStr.read(bytes, count, bytes.length - count);
             if (numRead < 0)
             {
                 throw new EOFException("premature end of stream");

Source: Bouncy Castle patch commit 37094e5

Detection Methods for CVE-2026-14682

Indicators of Compromise

  • Repeated java.lang.OutOfMemoryError: Java heap space events in application logs correlated with inbound TLS, certificate, or CMS parsing operations.
  • Stack traces referencing org.bouncycastle.asn1.DefiniteLengthInputStream or org.bouncycastle.util.io.Streams immediately before JVM termination.
  • Sudden JVM heap-usage spikes triggered by small inbound payloads carrying oversized ASN.1 length prefixes.

Detection Strategies

  • Inventory Java applications and inspect dependency manifests for bcprov, bc-fips, and bctls-fips artifacts below the fixed versions.
  • Instrument JVMs with heap-dump-on-OOM and monitor for allocation failures in processes handling untrusted ASN.1 or X.509 data.
  • Baseline normal request-to-heap-growth ratios on TLS terminators and certificate validators, and alert on anomalous single-request allocations.

Monitoring Recommendations

  • Enable Software Composition Analysis (SCA) rules that flag vulnerable org.bouncycastle:* versions in build pipelines.
  • Forward JVM garbage collection and OOM telemetry to your SIEM to correlate crashes with attacker sources.
  • Track ingress traffic to public-facing Java services for repeated short connections that terminate with server-side resource exhaustion.

How to Mitigate CVE-2026-14682

Immediate Actions Required

  • Upgrade Bouncy Castle for Java to 1.85 or later and Bouncy Castle for Java LTS to 2.73.12 or later.
  • Upgrade BC-FJA to bc-fips 1.0.2.7, 2.0.2, or 2.1.3 as appropriate for your release stream, and upgrade bctls-fips to 1.0.24.
  • Rebuild and redeploy any shaded or fat JARs that embed vulnerable Bouncy Castle classes.

Patch Information

The fix is delivered in commit 37094e5. It replaces the eager new byte[_remaining] allocation in DefiniteLengthInputStream.toByteArray() with a call to Streams.readLenBytesFully(), which grows its buffer incrementally as bytes actually arrive. See the Bouncy Castle CVE-2026-14682 advisory for full version guidance.

Workarounds

  • Enforce strict maximum message sizes upstream of Bouncy Castle parsing, using reverse proxies or protocol-aware gateways to drop oversized ASN.1 payloads.
  • Constrain JVM heap and apply per-request memory quotas so a single malicious message cannot exhaust process memory.
  • Restrict network exposure of services that parse untrusted ASN.1, X.509, or CMS data until patched builds are deployed.
bash
# Verify installed Bouncy Castle versions in a Maven project
mvn dependency:tree -Dincludes=org.bouncycastle

# Force upgrade via Maven dependency management
# pom.xml <dependencyManagement> entry
# <dependency>
#   <groupId>org.bouncycastle</groupId>
#   <artifactId>bcprov-jdk18on</artifactId>
#   <version>1.85</version>
# </dependency>

# Gradle equivalent
# implementation('org.bouncycastle:bcprov-jdk18on:1.85')

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.