CVE-2026-64958
Patch Available.
This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.
Overview
Apache CXF is an open-source services framework, maintained by the Apache Software Foundation, for building and consuming web services in Java. It implements the JAX-WS and JAX-RS APIs and supports SOAP, the WS-* standards, RESTful HTTP, and OAuth 2.0 over transports such as HTTP and JMS. Its modules are published as Maven artifacts under org.apache.cxf.
A Denial of Service (DoS) vulnerability (CVE-2026-64958) has been identified in the multipart attachment handling of Apache CXF (the LazyAttachmentCollection class in cxf-core and the JAX-RS MessageContextImpl in cxf-rt-frontend-jaxrs), which allows attackers to exhaust server memory and processing resources by sending a single multipart message containing a very large number of attachments. The advisory describes it as an incomplete fix for CVE-2026-50645. Several code paths read and store attachments without checking the configured attachment-max-count limit.
Per OWASP: The Denial of Service (DoS) attack is focused on making a resource (site, application, server) unavailable for the purpose it was designed.
This issue affects all versions prior to 3.6.12, versions 4.0.0 through 4.1.7, and versions 4.2.0 through 4.2.2 of Apache CXF.
Details
Module Info
- Product: Apache CXF
- Affected packages:
org.apache.cxf:cxf-core - Affected versions: <3.6.12, >=4.0.0 <4.1.8, >=4.2.0 <4.2.3
- GitHub repository: https://github.com/apache/cxf
- Published packages: https://central.sonatype.com/artifact/org.apache.cxf/cxf-core
- Package manager: Maven
- Fixed in:
- OSS Apache CXF 3.6.12, 4.1.8, 4.2.3
- NES for Apache CXF v3.5.13, v3.4.12
Vulnerability Info
This High-severity vulnerability is found in the cxf-core package in all versions prior to 3.6.12, versions 4.0.0 through 4.1.7, and versions 4.2.0 through 4.2.2 of Apache CXF.
Apache CXF limits the number of attachments it will accept in a multipart (MIME/MTOM or multipart/form-data) message through the attachment-max-count contextual property, which defaults to 50. That limit is only enforced inside LazyAttachmentCollection.loadAll(), which runs when the collection's size is requested. The other methods that pull attachments off the wire with deserializer.readNext(), namely hasNext(boolean) and the collection's iterator(), keep reading and storing attachments with no count check, and add and addAll accept any number of entries:
public boolean hasNext(boolean shouldLoadNew) throws IOException {
if (shouldLoadNew) {
Attachment a = deserializer.readNext();
if (a != null) {
attachments.add(a);
return true;
}
return false;
}
return deserializer.hasNext();
}
// ...
public Iterator<Attachment> iterator() {
return new Iterator<Attachment>() {
int current;
boolean removed;
public boolean hasNext() {
if (attachments.size() > current) {
return true;
}
// check if there is another attachment
try {
Attachment a = deserializer.readNext();
if (a == null) {
return false;
}
attachments.add(a);
return true;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// ...
};
}
public boolean add(Attachment arg0) {
return attachments.add(arg0);
}
public boolean addAll(Collection<? extends Attachment> arg0) {
return attachments.addAll(arg0);
}
Any consumer that iterates the message attachments (for example, the JAX-RS multipart support and MTOM/SwA processing) therefore walks the entire attacker-supplied body, allocating an Attachment object (and buffering its content in memory or in temporary files) for every part.
The JAX-RS frontend is one such consumer. MessageContextImpl.createAttachments, which backs MultipartBody injection for JAX-RS resources, walks the child attachments with the collection's iterator() and adds every one to the MultipartBody, with no count check of its own. When it processes an embedded multipart payload it also creates a fresh message that carries over the directory, memory threshold, maximum size, and maximum header size settings, but not attachment-max-count:
if (embeddedAttachment) {
inMessage = new MessageImpl();
inMessage.setExchange(new ExchangeImpl());
...
inMessage.put(AttachmentDeserializer.ATTACHMENT_MAX_HEADER_SIZE,
m.getExchange().getInMessage().get(AttachmentDeserializer.ATTACHMENT_MAX_HEADER_SIZE));
inMessage.setContent(InputStream.class,
m.getExchange().getInMessage().get("org.apache.cxf.multipart.embedded.input"));
// ...
}
new AttachmentInputInterceptor().handleMessage(inMessage);
List<Attachment> newAttachments = new LinkedList<>();
// ...
for (org.apache.cxf.message.Attachment a : childAttachments) {
newAttachments.add(new Attachment(a, new ProvidersImpl(inMessage)));
}
The fix is in cxf-core: LazyAttachmentCollection now enforces the limit on every read path. The accompanying change to MessageContextImpl in cxf-rt-frontend-jaxrs adds a second check to this loop and passes attachment-max-count to embedded messages. An unauthenticated remote attacker who can send a multipart request to a CXF SOAP or JAX-RS endpoint can include thousands of small parts. CXF parses and retains all of them, consuming heap, CPU, and temporary disk space until the server becomes unresponsive or fails with an out-of-memory error.
Mitigation
Only recent versions of Apache CXF receive community support. Older lines are End-of-Life and will not receive public updates to address this issue.
Users of the affected components should apply one of the following mitigations:
- Upgrade to a currently supported Apache CXF release line (3.6.x or later) that contains the fix.
- Leverage a commercial support partner like HeroDevs for post-EOL security support.
Credits
- Markus Vogl from RISE GmbH (finder)