-
Notifications
You must be signed in to change notification settings - Fork 603
CVE 2026 103600
Issue affecting: BC C# .NET 2.6.2 and earlier, and the 2.7.0-beta.98 pre-release.
Fixed versions: BC C# .NET 2.7.0
Platform affected: All CLRs.
The ASN.1 parser placed no limit on how deeply constructed encodings (SEQUENCE, SET, constructed tagged objects and constructed strings) could be nested. Asn1InputStream and Asn1StreamParser handle each nested element with a further recursive call, for definite-length (DER) and indefinite-length (BER) encodings alike, so the depth of the recursion was chosen by whoever produced the input.
An encoding made of nothing but nested SEQUENCE headers is enough to exhaust the thread stack: about 2,000 levels, or 8 KB of DER, on the 1.5 MB stack .NET gives the main thread on Windows. The resulting StackOverflowException cannot be caught in .NET, so the whole process is terminated, not just the operation that was parsing the input. On threads with larger stacks the same input instead costs CPU time that grows with the square of the nesting depth, about 9 seconds for a 64 KB input.
Any application that parses ASN.1 from an untrusted source is exposed, whichever higher-level API it goes through: X.509 certificates and CRLs, CMS/PKCS#7 and S/MIME, PKCS#8 and PKCS#12, OCSP, time-stamps, and certificates received during a TLS handshake (the default 32 KB limit on TLS handshake messages is not small enough to prevent it).
BC C# .NET 2.7.0 limits the nesting depth of constructed encodings to 64 by default. More deeply nested input is rejected with an Asn1Exception, which is an IOException, so callers that already handle malformed input need no changes. The limit can be adjusted with the property "Org.BouncyCastle.Asn1.MaxDepth", set either as an environment variable or per thread through Org.BouncyCastle.Utilities.Properties.
Earlier versions have no setting that prevents this, so upgrading is recommended. Where that is not immediately possible, untrusted input should be checked before it is passed to Bouncy Castle and rejected if it nests constructed elements more deeply than the application expects; legitimate structures stay well within the new default of 64. Limiting the size of the input alone is not enough, given how little input is needed. Parsing on a thread created with a larger stack avoids the process termination but not the CPU cost.
The corresponding problem in BC Java was addressed in BC Java 1.84, with a follow-up fix in BC Java 1.85 (CVE-2026-13506).
Fix Commits:
- https://github.com/bcgit/bc-csharp/commit/89c81b0da7fe11cd70013285560bbc472cb73901 (adds the depth limit)
- https://github.com/bcgit/bc-csharp/commit/b99f4e3dcea05b57becc79dfa6ad91a54c778d65 (sets the default to 64)
Credit: Yt.