CVE-2026-90852 Overview
CVE-2026-90852 is a use-after-free vulnerability in the luben zstd-jni library, a Java Native Interface (JNI) binding for the Zstandard compression library. The flaw affects the ZstdCompressCtx.loadDict function in ZstdCompressCtx.java within the Dictionary Sharing component. Versions up to and including 1.5.7-13 are affected. The vulnerability stems from incorrect lifetime tracking between shared dictionary objects and compression contexts. An attacker can trigger the condition remotely when the library processes attacker-influenced compression workloads. The maintainer released a fix in version 1.5.7-14, identified by patch commit a560131d7834598afd9cea6b7c107bc88e915936.
Critical Impact
Remote exploitation of the use-after-free condition can lead to memory corruption impacting confidentiality, integrity, and availability of applications embedding vulnerable versions of zstd-jni.
Affected Products
- luben zstd-jni versions up to and including 1.5.7-13
- The ZstdCompressCtx.loadDict function in ZstdCompressCtx.java
- Dictionary Sharing component of zstd-jni
Discovery Timeline
- 2026-09-15 - CVE CVE-2026-90852 published to NVD
- 2026-09-15 - Last updated in NVD database
Technical Details for CVE-2026-90852
Vulnerability Analysis
The vulnerability is classified under [CWE-119] (Improper Restriction of Operations within the Bounds of a Memory Buffer) and manifests as a use-after-free in the Dictionary Sharing subsystem of zstd-jni. When a compression context loads a dictionary via ZstdCompressCtx.loadDict, the shared lock accounting on the dictionary object is released prematurely relative to the compression context's usage. If the dictionary is closed or garbage collected while a compression context still holds a native reference to it, the underlying native memory can be freed while still in use. Subsequent compression operations then dereference freed memory, leading to memory corruption. Because zstd-jni is widely embedded in JVM-based data pipelines, message brokers, and storage engines, remote inputs that trigger dictionary handling can reach this code path from the network.
Root Cause
The root cause is incorrect cross-object lifetime tracking between AutoCloseBase-derived dictionaries and compression contexts. The SHARED_LOCK_UPDATER compare-and-set logic in AutoCloseBase.java treated the shared lock as a single-owner flag rather than a reference counter. Combined with ZstdCompressCtx.loadDict releasing the shared lock on the new dictionary before assigning it to the persistent compression_dict field, the accounting could reach zero while a live reference remained.
Attack Vector
The attack is network-reachable and requires no authentication or user interaction. An adversary who can influence compression dictionary handling in an application using vulnerable zstd-jni can trigger the free-then-use sequence, corrupting the JVM's native heap.
// Security patch in src/main/java/com/github/luben/zstd/ZstdCompressCtx.java
if (Zstd.isError(result)) {
throw new ZstdException(result);
}
+ if (compression_dict != null) {
+ compression_dict.releaseSharedLock();
+ }
// keep a reference to the dictionary so it's not garbage collected
compression_dict = dict;
} finally {
- if (dict != null) {
- dict.releaseSharedLock();
- }
releaseSharedLock();
}
return this;
// Source: https://github.com/luben/zstd-jni/commit/a560131d7834598afd9cea6b7c107bc88e915936
A companion change in AutoCloseBase.java converts the shared lock into a proper reference count:
// Security patch in src/main/java/com/github/luben/zstd/AutoCloseBase.java
if (sharedLock == SHARED_LOCK_CLOSED) {
return;
}
- if (!SHARED_LOCK_UPDATER.compareAndSet(this, 0, SHARED_LOCK_CLOSED)) {
- throw new IllegalStateException("Attempt to close while in use");
+ if (sharedLock > 0) {
+ if (SHARED_LOCK_UPDATER.compareAndSet(this, sharedLock, sharedLock - 1)) {
+ if (sharedLock == 0) {
+ doClose();
+ }
+ }
}
- doClose();
}
// Source: https://github.com/luben/zstd-jni/commit/a560131d7834598afd9cea6b7c107bc88e915936
Detection Methods for CVE-2026-90852
Indicators of Compromise
- JVM crash logs (hs_err_pid*.log) referencing native frames inside libzstd-jni or ZSTD_compress* functions.
- Unexpected SIGSEGV or EXCEPTION_ACCESS_VIOLATION faults in Java processes performing Zstandard compression with dictionaries.
- Application logs showing IllegalStateException: Attempt to close while in use on AutoCloseBase-derived objects prior to patching.
Detection Strategies
- Inventory JVM applications and dependencies for com.github.luben:zstd-jni versions at or below 1.5.7-13 using software composition analysis (SCA) tooling.
- Scan container images and build artifacts for the vulnerable zstd-jni JAR fingerprint and flag any deployments referencing pre-1.5.7-14 releases.
- Correlate JVM crash telemetry with active use of ZstdDictCompress or ZstdCompressCtx.loadDict code paths in application traces.
Monitoring Recommendations
- Enable JVM crash reporting and forward hs_err_pid*.log files to a centralized log platform for review.
- Monitor process stability metrics for Java services that ingest attacker-influenced data through compression pipelines.
- Track dependency updates in CI/CD to alert on any regression to zstd-jni versions prior to 1.5.7-14.
How to Mitigate CVE-2026-90852
Immediate Actions Required
- Upgrade com.github.luben:zstd-jni to version 1.5.7-14 or later across all applications, containers, and build pipelines.
- Rebuild and redeploy shaded or fat JARs that bundle zstd-jni to ensure the patched version is actually loaded at runtime.
- Audit third-party libraries and platforms that transitively depend on zstd-jni and apply vendor updates as they become available.
Patch Information
The fix is available in GitHub Release v1.5.7-14 and corresponds to commit a560131d. The patch corrects cross-object lifetime tracking between dictionaries and compression contexts by converting the shared lock into a reference count and reordering the releaseSharedLock call in ZstdCompressCtx.loadDict. Additional context is documented in GitHub Issue #404 and the VulDB entry for CVE-2026-90852.
Workarounds
- Avoid loading Zstandard dictionaries from untrusted or network-derived sources until the patched version is deployed.
- Where feasible, disable dictionary-based compression in application configuration and fall back to dictionary-less Zstandard streams.
- Isolate services that rely on zstd-jni behind trust boundaries so that only vetted inputs reach the compression path.
# Maven dependency update to the patched release
# pom.xml
<dependency>
<groupId>com.github.luben</groupId>
<artifactId>zstd-jni</artifactId>
<version>1.5.7-14</version>
</dependency>
# Gradle dependency update
# build.gradle
implementation 'com.github.luben:zstd-jni:1.5.7-14'
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.