CVE-2026-115906: CVE-2026-115906: AES Entry HMAC Authentication Bypass in Rust zip Crate
CVE-2026-115906: AES Entry HMAC Authentication Bypass in Rust zip Crate Vulnerability ID: CVE-2026-115906 CVSS Score: 6.5 Published: 2026-10-29 CVE-2026-115906 is a cryptographic authentication bypass vulnerability
CVE-2026-115906: AES Entry HMAC Authentication Bypass in Rust zip Crate
Vulnerability ID: CVE-2026-115906
CVSS Score: 6.5
Published: 2026-10-29
CVE-2026-115906 is a cryptographic authentication bypass vulnerability in the Rust zip library (zip-rs/zip2) affecting versions from 0.6.0 prior to 9.0.0. In the WinZip AE-x AES decryption reader implementation within src/aes.rs, the HMAC-SHA1-80 authentication tag is only validated when the internal byte counter (data_remaining) decrements to exactly zero. Because this counter is initialized from the unauthenticated compressed_size header field, an attacker can craft a ZIP archive where the entry stream hits premature physical end-of-file (EOF) before data_remaining reaches zero, causing the reader to return Ok(0) and skip HMAC verification entirely.
TL;DR
The Rust zip crate prior to version 9.0.0 fails to verify the HMAC-SHA1-80 authentication tag on AES-encrypted ZIP entries if the underlying stream reaches premature EOF or if the payload length is zero. Combined with AES-CTR ciphertext malleability and omitted CRC-32 checks in AE-2 archives, an attacker without knowledge of the password can modify or forge encrypted archive entries to deliver arbitrary plaintext without detection.
β οΈ Exploit Status: POC
Technical Details
- Vulnerability Type: Cryptographic Authentication Bypass (CWE-354 / CWE-1284)
- Affected Component: WinZip AE-x AES Decryption Reader (src/aes.rs in Rust zip crate)
- Attack Vector: Network / Malicious ZIP Archive (AV:N/AC:L/PR:N/UI:R)
- CVSS v3.1 Score: 6.5 Medium
- EPSS Score: 0.151% (4.17th Percentile)
- Security Impact: High Integrity Compromise (Arbitrary Ciphertext Forgery / Truncation)
- Exploit Status: Proof-of-Concept Available in Upstream Tests
- Patched Version: zip 9.0.0
Affected Systems
- Rust applications using the zip crate (zip-rs/zip2) versions >= 0.6.0, < 9.0.0 to decrypt AES-encrypted ZIP entries
-
zip: >= 0.6.0, < 9.0.0 (Fixed in:
9.0.0)
Code Analysis
Commit: ec265db
Fix AES entry HMAC authentication bypass on premature EOF and zero-length entries, and validate compressed_size against AES metadata length.
File: src/aes.rs
@@ -140,15 +140,18 @@ impl<R: Read> AesReader<R> {
- pub const fn new(reader: R, aes_mode: AesMode, compressed_size: u64) -> AesReader<R> {
- let data_length = compressed_size
- - (PWD_VERIFY_LENGTH + AUTH_CODE_LENGTH + aes_mode.salt_length()) as u64;
-
- Self {
+ pub fn new(reader: R, aes_mode: AesMode, compressed_size: u64) -> ZipResult<AesReader<R>> {
+ let metadata_len = (PWD_VERIFY_LENGTH + AUTH_CODE_LENGTH + aes_mode.salt_length()) as u64;
+ // we accept 0 size data
+ if compressed_size < metadata_len {
+ return Err(invalid!("Compressed size of AES data is invalid"));
+ }
+ let data_length = compressed_size - metadata_len;
+ Ok(Self {
reader,
aes_mode,
data_length,
- }
+ })
}
@@ -245,6 +250,10 @@ impl<R: Read> Read for AesReaderValid<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if self.data_remaining == 0 {
+ // handle case were payload is empty
+ if self.data_length == 0 {
+ self.verify_hmac()?;
+ }
return Ok(0);
}
@@ -262,38 +271,48 @@ impl<R: Read> Read for AesReaderValid<R> {
if self.data_remaining == 0 {
+ self.verify_hmac()?;
+ } else if read == 0 && self.data_remaining > 0 {
+ return Err(Error::new(
+ ErrorKind::UnexpectedEof,
+ "Read 0 bytes of AES data but still contains remaining data",
+ ));
}
Exploit Details
- GitHub: Official regression test and Proof of Concept (hmac_is_bypassed_when_the_entry_ends_early and hmac_is_never_checked_for_a_zero_length_entry) included in the remediation commit.
Mitigation Strategies
- Upgrade the Rust zip crate dependency to version 9.0.0 or later to ensure premature EOF and zero-length payload conditions are properly checked during AES decryption.
- Implement pre-extraction structural validation on untrusted ZIP archives to verify that no entry's local header or declared compressed_size extends into the Central Directory or past the End of Central Directory (EOCD) record.
- Replace or supplement password-based ZIP AE-x encryption with detached digital signatures (e.g., Ed25519) or modern authenticated encryption containers (e.g., age) when archive integrity is security-critical.
Remediation Steps:
- Locate all Rust projects using the zip crate by scanning Cargo.lock files with 'cargo audit' or 'cargo tree -i zip'.
- Update Cargo.toml to specify zip = ">= 9.0.0" and run 'cargo update -p zip'.
- Run test suites to accommodate any major version API adjustments introduced between prior releases and v9.0.0.
- Rebuild and redeploy affected binaries and services.
References
- GitHub Advisory GHSA-8hxf-qr8p-62x4
- Official Fix Commit ec265db0b0602f8ffb9479327397bddefb7e2216
- zip v9.0.0 Release Notes
- NVD Vulnerability Detail: CVE-2026-115906
- CVE.org Record: CVE-2026-115906
- CVEProject cvelistV5 Record
- Wiz Vulnerability Database Advisory: CVE-2026-115906
Read the full report for CVE-2026-115906 on our website for more details including interactive diagrams and full exploit analysis.
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.