CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-HC3C-63HC-2R9F
7.5

GHSA-HC3C-63HC-2R9F: Denial of Service via Uncaught Exception in libcrux-chacha20poly1305

Amit Schendel
Amit Schendel
Senior Security Researcher

May 19, 2026·7 min read·1 visit

PoC Available

Executive Summary (TL;DR)

A missing length bound check in the libcrux-chacha20poly1305 encrypt function causes an unhandled panic when the provided destination buffer exceeds the required size. This leads to a Denial of Service via application termination.

The libcrux-chacha20poly1305 cryptographic crate contains a Denial of Service vulnerability triggered by providing an overlong ciphertext buffer during encryption. This flaw manifests as a runtime panic due to an improper slice conversion, allowing attackers to terminate the application if buffer sizes are user-influenced.

Cryptographic Context and Architecture

ChaCha20-Poly1305 is an Authenticated Encryption with Associated Data (AEAD) algorithm. The algorithm provides both confidentiality for the plaintext and cryptographic integrity for the entire message. The resulting output consists of the encrypted ciphertext and a dedicated authentication tag.

The standard size for a Poly1305 authentication tag is 16 bytes. Cryptographic libraries typically require the calling application to provide a destination buffer large enough to hold the combined ciphertext and tag. The ciphertext length always strictly equals the original plaintext length.

Memory management in Rust enforces strict bounds checking to prevent classic buffer overflow vulnerabilities. Cryptographic libraries often utilize raw slices and perform manual pointer arithmetic or slicing operations for performance reasons. These manual operations require precise calculations to avoid runtime panics when structural invariants are violated.

Vulnerability Overview

The vulnerability resides in the libcrux-chacha20poly1305 crate, specifically within its handling of AEAD encryption operations. The issue is tracked as CWE-248 (Uncaught Exception) and CWE-20 (Improper Input Validation). The flaw affects applications relying on this specific Rust crate for ChaCha20-Poly1305 AEAD encryption.

The library expects a pre-allocated destination buffer to write the resulting ciphertext and authentication tag. The vulnerability surfaces when this buffer is larger than strictly necessary for the operation. The encrypt routine fails to properly account for excess capacity within the provided mutable slice.

When the overlong buffer is processed, an internal type conversion fails, resulting in an explicit panic. This terminates the executing thread and leads to a Denial of Service (DoS) for the host application. An attacker with control over the input payload size relative to pre-allocated buffers can consistently trigger this state.

Root Cause Analysis

The bug originates within the encrypt function located in the libcrux_chacha20poly1305::impl_hacl module. The function accepts a mutable slice reference named ctxt designed to hold both the ciphertext and the appended authentication tag. The implementation uses the split_at_mut method to partition this buffer based on the plaintext length.

After partitioning, the code assumes the remaining portion of the buffer is exactly the size of the authentication tag, which is 16 bytes (TAG_LEN). The code attempts to cast this remaining slice into a fixed-size array reference using the try_into() method. The standard library implementation of this trait requires exact size matching.

If the caller provides a buffer that exceeds ptxt_len + TAG_LEN, the remaining slice length will be greater than 16 bytes. The try_into() method returns an Err variant because the slice length does not exactly match the target array size. The conversion is subsequently rejected by the Rust type system.

The immediate trigger occurs because the code appends .unwrap() directly to the try_into() call. Since the conversion fails and returns an Err, the unwrap operation executes its panic branch. This immediately unwinds the stack and crashes the current thread.

Code Analysis and Patch Verification

The vulnerable implementation fundamentally mismanages the bounds of the provided mutable slice. The following code snippet demonstrates the exact point of failure within the encrypt routine. The tag variable absorbs all excess bytes from the oversized buffer.

// Vulnerable Implementation
let (ctxt_cpa, tag) = ctxt.split_at_mut(ptxt_len as usize);
// If ctxt length > ptxt_len + 16, tag length will be > 16.
// The unwrap() call will panic when try_into() returns Err.
let tag: &mut [u8; TAG_LEN] = tag.try_into().unwrap();

The patch introduced in Pull Request #1386 resolves the panic by performing a secondary partition on the remainder of the buffer. This ensures the target slice is exactly TAG_LEN bytes before the conversion attempt. Any excess bytes are explicitly discarded into a generic _rest variable.

-    // ensure destination slice has just the right length
-    let (ctxt_cpa, tag) = ctxt.split_at_mut(ptxt_len as usize);
+    let (ctxt_cpa, rest) = ctxt.split_at_mut(ptxt_len as usize);
+    // The ciphertext buffer may be longer than ptxt_len + TAG_LEN.
+    let (tag, _rest) = rest.split_at_mut(TAG_LEN);
     let tag: &mut [u8; TAG_LEN] = tag.try_into().unwrap();

This fix successfully neutralizes the panic condition by guaranteeing the try_into() operation receives a slice of exactly 16 bytes. The compiler can safely convert the properly sized slice without encountering the Err variant, restoring standard operational stability.

Exploitation Methodology

Exploitation requires the attacker to influence the size of the buffer passed to the cryptographic operation. Network services frequently pre-allocate fixed-size buffers for performance reasons, intending to fill only the required portion with ciphertext. If the system does not dynamically resize the slice to the exact required length before passing it to libcrux, the vulnerability becomes reachable.

An attacker can trigger this condition by sending a malformed request that manipulates the plaintext length relative to a fixed-size response buffer. The specific mechanism depends entirely on the implementation of the wrapping application. The attacker needs the application to supply a ctxt slice where the length is strictly greater than the plaintext length plus 16 bytes.

The following state transition diagram illustrates the control flow during a successful denial of service attack. The attacker sends a request designed to mismatch the plaintext and buffer lengths, leading directly to the termination sequence.

Impact Assessment

The direct consequence of this vulnerability is a Denial of Service. In Rust, a panic unwinds the stack and terminates the current thread. If the application does not utilize a panic-catching mechanism at the thread boundary, the entire process will exit unexpectedly.

This flaw is particularly problematic for network daemons or microservices processing concurrent requests. A single crafted packet can terminate the service, requiring a restart by the orchestration system. Continuous exploitation prevents the service from maintaining availability, severing legitimate user access.

The vulnerability does not provide arbitrary code execution or memory corruption capabilities. The Rust compiler's bounds checking and the deterministic nature of panics restrict the impact exclusively to availability. Data confidentiality and system integrity remain uncompromised.

Remediation and Mitigation Guidance

The vulnerability is completely resolved in libcrux-chacha20poly1305 version 0.0.8 and later. The developers implemented robust slice partitioning that defensively isolates the required memory segments regardless of the overall buffer capacity. Development teams must update their dependency manifests to require the patched version.

If immediate dependency updates are not feasible, developers can mitigate the issue within their application logic. The application must guarantee that the mutable slice passed to the encrypt function is exactly sized. Developers can achieve this by truncating the slice prior to the function call.

// Mitigation implementation in calling code
let required_len = ptxt.len() + 16;
let exact_ctxt = &mut ctxt_buffer[..required_len];
// Safe to call with properly sized buffer
libcrux_chacha20poly1305::encrypt(key, exact_ctxt, ptxt, aad);

Security teams should audit codebases for fixed-size buffer allocations used in conjunction with cryptographic routines. Ensuring strict alignment between data sizes and allocated slices minimizes the attack surface for similar logic errors across the application suite.

Official Patches

CryspenFix Pull Request for libcrux
CryspenRaw patch file for PR 1386

Fix Analysis (1)

Technical Appendix

CVSS Score
7.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Affected Systems

Rust applications utilizing libcrux-chacha20poly1305 versions <= 0.0.7 for encryption tasks

Affected Versions Detail

Product
Affected Versions
Fixed Version
libcrux-chacha20poly1305
Cryspen
<= 0.0.70.0.8
AttributeDetail
CWE IDCWE-248, CWE-20
Attack VectorNetwork / Local
CVSS Score7.5 (High)
ImpactDenial of Service (DoS)
Exploit StatusProof of Concept Available
CISA KEVNot Listed

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
CWE-248
Uncaught Exception

An uncaught exception in the application logic allows an attacker to trigger a thread panic.

Vulnerability Timeline

Release of version 0.0.7 of libcrux-chacha20poly1305
2026-03-19
Vulnerability reported by user @fg0x0 and Pull Request #1386 submitted
2026-04-14
Security advisory published via RustSec and GitHub
2026-05-13

References & Sources

  • [1]GitHub Advisory: GHSA-HC3C-63HC-2R9F
  • [2]RustSec Advisory: RUSTSEC-2026-0124
  • [3]Cryspen libcrux Pull Request #1386
  • [4]Cryspen libcrux Official Repository

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.