CVE-2019-17638
Description
In Eclipse Jetty, versions 9.4.27.v20200227 to 9.4.29.v20200521, in case of too large response headers, Jetty throws an exception to produce an HTTP 431 error. When this happens, the ByteBuffer containing the HTTP response headers is released back to the ByteBufferPool twice. Because of this double release, two threads can acquire the same ByteBuffer from the pool and while thread1 is about to use the ByteBuffer to write response1 data, thread2 fills the ByteBuffer with other data. Thread1 then proceeds to write the buffer that now contains different data. This results in client1, which issued request1 seeing data from another request or response which could contain sensitive data belonging to client2 (HTTP session ids, authentication credentials, etc.). If the Jetty version cannot be upgraded, the vulnerability can be significantly reduced by configuring a responseHeaderSize significantly larger than the requestHeaderSize (12KB responseHeaderSize and 8KB requestHeaderSize).
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Eclipse Jetty 9.4.27-9.4.29 double-releases ByteBuffer on response header overflow, causing buffer corruption and potential cross-client data leakage.
Vulnerability
Description
In Eclipse Jetty versions 9.4.27.v20200227 through 9.4.29.v20200521, when a response header exceeds the configured maximum size, Jetty throws an exception to produce an HTTP 431 error. During this error handling, the ByteBuffer containing the HTTP response headers is released back to the ByteBufferPool twice. This double release allows two threads to acquire the same ByteBuffer from the pool concurrently [1][2].
Exploitation
Conditions
An attacker can trigger the vulnerability by sending a request that causes the server to generate response headers larger than the limit (e.g., via a crafted request that results in many or large headers). When the 431 error occurs, the buffer is freed twice. Under concurrent load, a second thread may allocate the same buffer and fill it with data from a different request or response. The first thread then writes the now-corrupted buffer, causing data intended for one client to be sent to another [2][4].
Impact
A client that issued a legitimate request may receive data from another client's request or response. This leaked data can include sensitive information such as HTTP session IDs, authentication credentials, or other confidential content [1][2]. The vulnerability has a CVSS score of 8.3 (High) and is associated with CWE-672 (Operation on a Resource after Expiration or Release) and CWE-675 (Duplicate Operations on Resource) [4].
Mitigation
The issue is fixed in Jetty versions 9.4.30.v20200611 and later [3]. If upgrading is not immediately possible, the risk can be significantly reduced by configuring the response header size to be substantially larger than the request header size (e.g., 12KB responseHeaderSize and 8KB requestHeaderSize) [1]. No workaround fully eliminates the vulnerability, but this configuration reduces the likelihood of triggering the double-release condition.
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.eclipse.jetty:jetty-serverMaven | >= 9.4.27, < 9.4.30.v20200611 | 9.4.30.v20200611 |
Affected products
2- The Eclipse Foundation/Eclipse Jettyv5Range: 9.4.27.v20200227 to 9.4.29.v20200521
Patches
1ff8ae56fa939Issue #4936 response buffer corruption (#4937)
2 files changed · +170 −23
jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java+28 −23 modified@@ -72,7 +72,6 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http private final HttpParser _parser; private final AtomicInteger _contentBufferReferences = new AtomicInteger(); private volatile ByteBuffer _requestBuffer = null; - private volatile ByteBuffer _chunk = null; private final BlockingReadCallback _blockingReadCallback = new BlockingReadCallback(); private final AsyncReadCallback _asyncReadCallback = new AsyncReadCallback(); private final SendCallback _sendCallback = new SendCallback(); @@ -442,11 +441,6 @@ else if (_parser.inContentState() && _generator.isPersistent()) _parser.close(); } - // Not in a race here with onFillable, because it has given up control before calling handle. - // in a slight race with #completed, but not sure what to do with that anyway. - if (_chunk != null) - _bufferPool.release(_chunk); - _chunk = null; _generator.reset(); // if we are not called from the onfillable thread, schedule completion @@ -693,6 +687,7 @@ private class SendCallback extends IteratingCallback private boolean _lastContent; private Callback _callback; private ByteBuffer _header; + private ByteBuffer _chunk; private boolean _shutdownOut; private SendCallback() @@ -737,10 +732,9 @@ public Action process() throws Exception if (_callback == null) throw new IllegalStateException(); - ByteBuffer chunk = _chunk; while (true) { - HttpGenerator.Result result = _generator.generateResponse(_info, _head, _header, chunk, _content, _lastContent); + HttpGenerator.Result result = _generator.generateResponse(_info, _head, _header, _chunk, _content, _lastContent); if (LOG.isDebugEnabled()) LOG.debug("generate: {} for {} ({},{},{})@{}", result, @@ -763,31 +757,29 @@ public Action process() throws Exception case HEADER_OVERFLOW: { - int capacity = _header.capacity(); - _bufferPool.release(_header); - if (capacity >= _config.getResponseHeaderSize()) + if (_header.capacity() >= _config.getResponseHeaderSize()) throw new BadMessageException(INTERNAL_SERVER_ERROR_500, "Response header too large"); + releaseHeader(); _header = _bufferPool.acquire(_config.getResponseHeaderSize(), HEADER_BUFFER_DIRECT); continue; } case NEED_CHUNK: { - chunk = _chunk = _bufferPool.acquire(HttpGenerator.CHUNK_SIZE, CHUNK_BUFFER_DIRECT); + _chunk = _bufferPool.acquire(HttpGenerator.CHUNK_SIZE, CHUNK_BUFFER_DIRECT); continue; } case NEED_CHUNK_TRAILER: { - if (_chunk != null) - _bufferPool.release(_chunk); - chunk = _chunk = _bufferPool.acquire(_config.getResponseHeaderSize(), CHUNK_BUFFER_DIRECT); + releaseChunk(); + _chunk = _bufferPool.acquire(_config.getResponseHeaderSize(), CHUNK_BUFFER_DIRECT); continue; } case FLUSH: { // Don't write the chunk or the content if this is a HEAD response, or any other type of response that should have no content if (_head || _generator.isNoContent()) { - BufferUtil.clear(chunk); + BufferUtil.clear(_chunk); BufferUtil.clear(_content); } @@ -798,10 +790,10 @@ public Action process() throws Exception gatherWrite += 4; bytes += _header.remaining(); } - if (BufferUtil.hasContent(chunk)) + if (BufferUtil.hasContent(_chunk)) { gatherWrite += 2; - bytes += chunk.remaining(); + bytes += _chunk.remaining(); } if (BufferUtil.hasContent(_content)) { @@ -812,10 +804,10 @@ public Action process() throws Exception switch (gatherWrite) { case 7: - getEndPoint().write(this, _header, chunk, _content); + getEndPoint().write(this, _header, _chunk, _content); break; case 6: - getEndPoint().write(this, _header, chunk); + getEndPoint().write(this, _header, _chunk); break; case 5: getEndPoint().write(this, _header, _content); @@ -824,10 +816,10 @@ public Action process() throws Exception getEndPoint().write(this, _header); break; case 3: - getEndPoint().write(this, chunk, _content); + getEndPoint().write(this, _chunk, _content); break; case 2: - getEndPoint().write(this, chunk); + getEndPoint().write(this, _chunk); break; case 1: getEndPoint().write(this, _content); @@ -871,10 +863,23 @@ private Callback release() _callback = null; _info = null; _content = null; + releaseHeader(); + releaseChunk(); + return complete; + } + + private void releaseHeader() + { if (_header != null) _bufferPool.release(_header); _header = null; - return complete; + } + + private void releaseChunk() + { + if (_chunk != null) + _bufferPool.release(_chunk); + _chunk = null; } @Override
jetty-server/src/test/java/org/eclipse/jetty/server/LargeHeaderTest.java+142 −0 added@@ -0,0 +1,142 @@ +// +// ======================================================================== +// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.server; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.net.Socket; +import java.util.Arrays; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpTester; +import org.eclipse.jetty.http.MimeTypes; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.server.handler.ErrorHandler; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.component.LifeCycle; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +public class LargeHeaderTest +{ + private Server server; + + @BeforeEach + public void setup() throws Exception + { + server = new Server(); + + HttpConfiguration config = new HttpConfiguration(); + HttpConnectionFactory http = new HttpConnectionFactory(config); + + ServerConnector connector = new ServerConnector(server, http); + connector.setPort(0); + connector.setIdleTimeout(5000); + server.addConnector(connector); + + server.setErrorHandler(new ErrorHandler()); + + server.setHandler(new AbstractHandler() + { + final String largeHeaderValue; + + { + byte[] bytes = new byte[8 * 1024]; + Arrays.fill(bytes, (byte)'X'); + largeHeaderValue = "LargeHeaderOver8k-" + new String(bytes, UTF_8) + "_Z_"; + } + + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException + { + response.setHeader(HttpHeader.CONTENT_TYPE.toString(), MimeTypes.Type.TEXT_HTML.toString()); + response.setHeader("LongStr", largeHeaderValue); + PrintWriter writer = response.getWriter(); + writer.write("<html><h1>FOO</h1></html>"); + writer.flush(); + response.flushBuffer(); + baseRequest.setHandled(true); + } + }); + server.start(); + } + + @AfterEach + public void teardown() + { + LifeCycle.stop(server); + } + + @Test + public void testLargeHeader() throws Throwable + { + final Logger CLIENTLOG = Log.getLogger(LargeHeaderTest.class).getLogger(".client"); + ExecutorService executorService = Executors.newFixedThreadPool(8); + + int localPort = server.getURI().getPort(); + String rawRequest = "GET / HTTP/1.1\r\n" + + "Host: localhost:" + localPort + "\r\n" + + "\r\n"; + + Throwable issues = new Throwable(); + + for (int i = 0; i < 500; ++i) + { + executorService.submit(() -> + { + try (Socket client = new Socket("localhost", localPort); + OutputStream output = client.getOutputStream(); + InputStream input = client.getInputStream()) + { + output.write(rawRequest.getBytes(UTF_8)); + output.flush(); + + String rawResponse = IO.toString(input, UTF_8); + HttpTester.Response response = HttpTester.parseResponse(rawResponse); + assertThat(response.getStatus(), is(500)); + } + catch (Throwable t) + { + CLIENTLOG.warn("Client Issue", t); + issues.addSuppressed(t); + } + }); + } + + executorService.awaitTermination(5, TimeUnit.SECONDS); + if (issues.getSuppressed().length > 0) + { + throw issues; + } + } +}
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
35- github.com/advisories/GHSA-x3rh-m7vp-35f2ghsaADVISORY
- lists.fedoraproject.org/archives/list/package-announce%40lists.fedoraproject.org/message/XE6US6VPZHOWFMUSFGDS5V2DNQPY5MKB/mitrevendor-advisoryx_refsource_FEDORA
- nvd.nist.gov/vuln/detail/CVE-2019-17638ghsaADVISORY
- www.openwall.com/lists/oss-security/2020/08/17/1ghsamailing-listx_refsource_MLISTWEB
- bugs.eclipse.org/bugs/show_bug.cgighsax_refsource_CONFIRMWEB
- github.com/eclipse/jetty.project/commit/ff8ae56fa939c3477a0cdd1ff56ce3d902f08fbaghsaWEB
- github.com/eclipse/jetty.project/issues/4936ghsaWEB
- lists.apache.org/thread.html/r29073905dc9139d0d7a146595694bf57bb9e35e5ec6aa73eb9c8443a%40%3Ccommits.pulsar.apache.org%3Emitremailing-listx_refsource_MLIST
- lists.apache.org/thread.html/r29073905dc9139d0d7a146595694bf57bb9e35e5ec6aa73eb9c8443a@%3Ccommits.pulsar.apache.org%3EghsaWEB
- lists.apache.org/thread.html/r378e4cdec15e132575aa1dcb6296ffeff2a896745a8991522e266ad4%40%3Ccommits.pulsar.apache.org%3Emitremailing-listx_refsource_MLIST
- lists.apache.org/thread.html/r378e4cdec15e132575aa1dcb6296ffeff2a896745a8991522e266ad4@%3Ccommits.pulsar.apache.org%3EghsaWEB
- lists.apache.org/thread.html/r4bdd3f7bb6820a79f9416b6667d718a06d269018619a75ce4b759318%40%3Ccommits.pulsar.apache.org%3Emitremailing-listx_refsource_MLIST
- lists.apache.org/thread.html/r4bdd3f7bb6820a79f9416b6667d718a06d269018619a75ce4b759318@%3Ccommits.pulsar.apache.org%3EghsaWEB
- lists.apache.org/thread.html/r521168299e023fb075b57afe33d17ff1d09e8a10e0fd8c775ea0e028%40%3Ccommits.pulsar.apache.org%3Emitremailing-listx_refsource_MLIST
- lists.apache.org/thread.html/r521168299e023fb075b57afe33d17ff1d09e8a10e0fd8c775ea0e028@%3Ccommits.pulsar.apache.org%3EghsaWEB
- lists.apache.org/thread.html/r7fc5f2ed49641ea91c433e3cd0fc3d31c0278c87b82b15c33b881415%40%3Ccommits.pulsar.apache.org%3Emitremailing-listx_refsource_MLIST
- lists.apache.org/thread.html/r7fc5f2ed49641ea91c433e3cd0fc3d31c0278c87b82b15c33b881415@%3Ccommits.pulsar.apache.org%3EghsaWEB
- lists.apache.org/thread.html/r81f58591fb4716fb867b36956f30c7c8ad4ab3f23abc952d9d86a2a0%40%3Ccommits.pulsar.apache.org%3Emitremailing-listx_refsource_MLIST
- lists.apache.org/thread.html/r81f58591fb4716fb867b36956f30c7c8ad4ab3f23abc952d9d86a2a0@%3Ccommits.pulsar.apache.org%3EghsaWEB
- lists.apache.org/thread.html/r9584c4304c888f651d214341a939bd264ed30c9e3d0d30fe85097ecf%40%3Ccommits.pulsar.apache.org%3Emitremailing-listx_refsource_MLIST
- lists.apache.org/thread.html/r9584c4304c888f651d214341a939bd264ed30c9e3d0d30fe85097ecf@%3Ccommits.pulsar.apache.org%3EghsaWEB
- lists.apache.org/thread.html/r9a2cfa56d30782a0c17a5deb951a622d1f5c8de48e1c3b578ffc2a84%40%3Ccommits.pulsar.apache.org%3Emitremailing-listx_refsource_MLIST
- lists.apache.org/thread.html/r9a2cfa56d30782a0c17a5deb951a622d1f5c8de48e1c3b578ffc2a84@%3Ccommits.pulsar.apache.org%3EghsaWEB
- lists.apache.org/thread.html/ra8661fc8c69c647cb06153c1485d48484a833d873f75dfe45937e9de%40%3Ccommits.pulsar.apache.org%3Emitremailing-listx_refsource_MLIST
- lists.apache.org/thread.html/ra8661fc8c69c647cb06153c1485d48484a833d873f75dfe45937e9de@%3Ccommits.pulsar.apache.org%3EghsaWEB
- lists.apache.org/thread.html/rbe1f230e87ea947593145d0072d0097ddb0af10fee1161db8ca1546c%40%3Ccommits.pulsar.apache.org%3Emitremailing-listx_refsource_MLIST
- lists.apache.org/thread.html/rbe1f230e87ea947593145d0072d0097ddb0af10fee1161db8ca1546c@%3Ccommits.pulsar.apache.org%3EghsaWEB
- lists.apache.org/thread.html/rd0e44e8ef71eeaaa3cf3d1b8b41eb25894372e2995ec908ce7624d26%40%3Ccommits.pulsar.apache.org%3Emitremailing-listx_refsource_MLIST
- lists.apache.org/thread.html/rd0e44e8ef71eeaaa3cf3d1b8b41eb25894372e2995ec908ce7624d26@%3Ccommits.pulsar.apache.org%3EghsaWEB
- lists.apache.org/thread.html/rd98cfd012490cb02caa1a11aaa0cc38bff2d43bcce9b20c2f01063dd%40%3Ccommits.pulsar.apache.org%3Emitremailing-listx_refsource_MLIST
- lists.apache.org/thread.html/rd98cfd012490cb02caa1a11aaa0cc38bff2d43bcce9b20c2f01063dd@%3Ccommits.pulsar.apache.org%3EghsaWEB
- lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/XE6US6VPZHOWFMUSFGDS5V2DNQPY5MKBghsaWEB
- snyk.io/vuln/SNYK-JAVA-ORGECLIPSEJETTY-575561ghsaWEB
- www.oracle.com/security-alerts/cpuApr2021.htmlghsax_refsource_MISCWEB
- www.oracle.com/security-alerts/cpuoct2020.htmlghsax_refsource_MISCWEB
News mentions
1- Jenkins Security Advisory 2020-08-17Jenkins Security Advisories · Aug 17, 2020