VYPR
Medium severityNVD Advisory· Published Jun 4, 2026· Updated Jun 4, 2026

CVE-2026-48040

CVE-2026-48040

Description

A vulnerability in netty-incubator-codec-ohttp allows attackers to corrupt memory and disclose sensitive data by triggering cryptographic operations with crafted requests.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

A vulnerability in netty-incubator-codec-ohttp allows attackers to corrupt memory and disclose sensitive data by triggering cryptographic operations with crafted requests.

Vulnerability

The netty-incubator-codec-ohttp library, versions prior to 0.0.22.Final, implements Oblivious HTTP (RFC 9458) using BoringSSL's HPKE C library via JNI. A fallback path for direct ByteBufs that do not expose their memory address via hasMemoryAddress() is triggered when sun.misc.Unsafe is unavailable, such as when the JVM is started with -Dio.netty.noUnsafe=true, a SecurityManager restricts Unsafe access, or non-HotSpot JVMs are used. In these configurations, PooledDirectByteBuf instances are returned where hasMemoryAddress() is false, leading to incorrect native memory address derivation for cryptographic operations [2].

Exploitation

An unauthenticated network attacker can exploit this vulnerability by sending crafted OHTTP requests to the OHTTP gateway. This triggers cryptographic operations that utilize the flawed native memory address derivation. The corruption and potential data disclosure occur regardless of whether the AEAD tag verification succeeds, as BoringSSL zeroizes the output buffer on failure [2].

Impact

Successful exploitation allows an attacker to corrupt memory belonging to other concurrent connections and disclose the contents of adjacent pooled direct buffers. The information disclosure path can provide the attacker with the encryption key needed to extract leaked data. This violates the confidentiality and integrity of all connections sharing the same Netty buffer arena [2].

Mitigation

Version 0.0.22.Final of netty-incubator-codec-ohttp addresses this issue. The specific commit that fixes the vulnerability is available at [1]. No workarounds are mentioned in the available references. The end-of-life status and whether it is listed on the KEV catalog are not yet disclosed in the available references.

AI Insight generated on Jun 4, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

2

Patches

1
7ad38d5cc282

Merge commit from fork

https://github.com/netty/netty-incubator-codec-ohttpNorman MaurerJun 3, 2026via nvd-ref
3 files changed · +55 9
  • codec-ohttp-hpke-classes-boringssl/src/main/java/io/netty/incubator/codec/hpke/boringssl/BoringSSLAEADContext.java+1 1 modified
    @@ -132,7 +132,7 @@ void incrementSequence() throws CryptoException {
             long computeNext(ByteBufAllocator alloc) {
                 if (nonce == null) {
                     nonce = alloc.directBuffer(baseNonce.length).writeBytes(baseNonce);
    -                nonceAddress = BoringSSL.memory_address(nonce);
    +                nonceAddress = BoringSSL.readerMemoryAddress(nonce);
                 }
     
                 for (int idx = 0, idx2 = baseNonce.length - 8 ; idx < 8; ++idx, ++idx2) {
    
  • codec-ohttp-hpke-classes-boringssl/src/main/java/io/netty/incubator/codec/hpke/boringssl/BoringSSLCryptoOperation.java+3 3 modified
    @@ -48,11 +48,11 @@ final boolean execute(long ctx, ByteBufAllocator alloc, ByteBuf aad, ByteBuf in,
                 int maxOutLen = maxOutLen(ctx, in.readableBytes());
                 directOut = directWritable(alloc, out, maxOutLen);
     
    -            long directAadAddress = BoringSSL.memory_address(directAad) + directAad.readerIndex();
    +            long directAadAddress = BoringSSL.readerMemoryAddress(directAad);
                 int directAddReadableBytes = directAad.readableBytes();
    -            long directInAddress = BoringSSL.memory_address(directIn) + directIn.readerIndex();
    +            long directInAddress = BoringSSL.readerMemoryAddress(directIn);
                 int directInReadableBytes = directIn.readableBytes();
    -            long directOutAddress = BoringSSL.memory_address(directOut) + directOut.writerIndex();
    +            long directOutAddress = BoringSSL.writerMemoryAddress(directOut);
                 int directOutWritableBytes = directOut.writableBytes();
                 int result = execute(ctx, alloc, directAadAddress, directAddReadableBytes,
                         directInAddress, directInReadableBytes,
    
  • codec-ohttp-hpke-classes-boringssl/src/main/java/io/netty/incubator/codec/hpke/boringssl/BoringSSL.java+51 5 modified
    @@ -116,7 +116,7 @@ static native byte[] EVP_HPKE_CTX_export(
     
         static native int EVP_HPKE_KEM_public_key_len(long kem);
     
    -    static native long memory_address(ByteBuffer buffer);
    +    private static native long memory_address(ByteBuffer buffer);
     
         static native int EVP_AEAD_key_length(long aead);
         static native int EVP_AEAD_nonce_length(long aead);
    @@ -138,11 +138,57 @@ static native int EVP_AEAD_CTX_open(
     
         static native byte[] HKDF_expand(long digest, int out_len, byte[] prk, byte[] info);
     
    -    static long memory_address(ByteBuf buffer) {
    -        if (buffer.hasMemoryAddress()) {
    -            return buffer.memoryAddress();
    +    /**
    +     * Returns the memory address if the {@link ByteBuf} taking the readerIndex into account.
    +     *
    +     * @param buf   the {@link ByteBuf} of which we want to obtain the memory address
    +     *              (taking its {@link ByteBuf#readerIndex()} into account).
    +     * @return      the memory address of this {@link ByteBuf}s readerIndex.
    +     */
    +    static long readerMemoryAddress(ByteBuf buf) {
    +        return memoryAddress(buf, buf.readerIndex(), buf.readableBytes());
    +    }
    +
    +    /**
    +     * Returns the memory address if the {@link ByteBuf} taking the writerIndex into account.
    +     *
    +     * @param buf   the {@link ByteBuf} of which we want to obtain the memory address
    +     *              (taking its {@link ByteBuf#writerIndex()} into account).
    +     * @return      the memory address of this {@link ByteBuf}s writerIndex.
    +     */
    +    static long writerMemoryAddress(ByteBuf buf) {
    +        return memoryAddress(buf, buf.writerIndex(), buf.writableBytes());
    +    }
    +
    +    /**
    +     * Returns the memory address if the {@link ByteBuf} taking the offset into account.
    +     *
    +     * @param buf       the {@link ByteBuf} of which we want to obtain the memory address
    +     *                  (taking the {@code offset} into account).
    +     * @param offset    the offset of the memory address.
    +     * @param len       the length of the {@link ByteBuf}.
    +     * @return          the memory address of this {@link ByteBuf}s offset.
    +     */
    +    static long memoryAddress(ByteBuf buf, int offset, int len) {
    +        assert buf.isDirect();
    +        if (buf.hasMemoryAddress()) {
    +            return buf.memoryAddress() + offset;
             }
    -        return memory_address(buffer.internalNioBuffer(0, buffer.capacity()));
    +        return memoryAddressWithPosition(buf.internalNioBuffer(offset, len));
    +    }
    +
    +    /**
    +     * Returns the memory address of the given {@link ByteBuffer} taking its current {@link ByteBuffer#position()} into
    +     * account.
    +     *
    +     * @param buf   the {@link ByteBuffer} of which we want to obtain the memory address
    +     *              (taking its {@link ByteBuffer#position()} into account).
    +     * @return      the memory address of this {@link ByteBuffer}s position.
    +     */
    +    static long memoryAddressWithPosition(ByteBuffer buf) {
    +        assert buf.isDirect();
    +        // We need to add the position as well as the JNI variant will return the base address.
    +        return memory_address(buf) + buf.position();
         }
     
         static long EVP_HPKE_CTX_new_or_throw() {
    

Vulnerability mechanics

Root cause

"The library incorrectly derives native memory addresses for cryptographic operations when `sun.misc.Unsafe` is unavailable, leading to out-of-bounds memory access."

Attack vector

An unauthenticated network attacker can trigger this vulnerability by sending crafted OHTTP requests to the OHTTP gateway. This occurs when the Java Virtual Machine is configured in a way that prevents Netty from using `sun.misc.Unsafe`, such as with `-Dio.netty.noUnsafe=true` or restricted SecurityManager policies. The crafted requests lead to memory corruption and potential information disclosure from adjacent pooled direct buffers.

Affected code

The vulnerability lies within the `io.netty.incubator.codec.hpke.boringssl` package, specifically in how memory addresses are obtained for cryptographic operations. The `BoringSSL.java` file's `memory_address` method and its usage in `BoringSSLCryptoOperation.java` and `BoringSSLAEADContext.java` are affected. The patch modifies these areas to correctly handle memory addressing.

What the fix does

The patch modifies the `BoringSSL.java` file to correctly account for the buffer's position and readable/writable bytes when deriving memory addresses via JNI. New methods like `readerMemoryAddress` and `writerMemoryAddress` are introduced to ensure that the correct offset is used, preventing out-of-bounds reads or writes. This resolves the memory corruption and information disclosure issues by ensuring cryptographic operations use valid memory regions [patch_id=4827862].

Preconditions

  • configThe JVM must be started with configurations that prevent Netty from using `sun.misc.Unsafe`, such as `-Dio.netty.noUnsafe=true`, a SecurityManager restricting Unsafe access, or running on non-HotSpot JVMs.
  • networkThe attacker must be able to send crafted OHTTP requests to the vulnerable gateway.

Generated on Jun 4, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

2

News mentions

1