Federico Mariani created CAMEL-24184:
----------------------------------------
Summary: camel-cxf - Umbrella: medium-severity findings from July
2026 code review
Key: CAMEL-24184
URL: https://issues.apache.org/jira/browse/CAMEL-24184
Project: Camel
Issue Type: Task
Components: camel-cxf
Reporter: Federico Mariani
Assignee: Federico Mariani
Umbrella tracking the *medium-severity* findings from the July 2026 AI-assisted
code review of the {{components/camel-cxf/}} component family. The
high-severity findings are filed as separate linked issues. Each item below has
been verified against current source and git history; items marked *[verified]*
were additionally re-read line-by-line on {{main}}.
h2. camel-cxf-soap / camel-cxf-common
# *replaceMultiPartContentType strips 5 extra characters* _[verified]_ -
{{DefaultCxfBinding.java:~869}}: for an unquoted {{type=}} parameter the value
has {{type=}} removed, then {{substring(5)}} is applied again, so
{{type=text/xml}} becomes {{xml}}. Corrupts the propagated {{Content-Type}} for
unquoted MTOM/multipart responses. Fix: {{result = part;}} in the else branch.
# *CxfClientCallback NPE when out message absent* -
{{CxfClientCallback.java:~88-97}}: with a failover {{ConduitSelector}} and a
transport error before the out message exists,
{{cxfExchange.getOutMessage().getContent(..)}} NPEs and replaces the real
exception. Fix: null-guard the out message.
# *populateCxfHeaderFromCamelExchangeBeforeCheckError is a no-op* -
{{DefaultCxfBinding.java:~456-479}}: called before the out message is created,
so its guarded {{put}} is skipped and response protocol headers are never
propagated onto a fault response. Fix: create/lookup the out (or fault) message
first, or move propagation into the fault path.
# *Unsynchronized lazy Bus creation* - {{CxfEndpoint.java:~1015-1047}}: the
{{bus}} field is non-volatile; concurrent producer/consumer {{doStart}} can
each create a Bus and leak one. Fix: volatile + double-checked locking, or init
in {{doInit}}.
h2. camel-cxf-rest
# *Void.class vs Void.TYPE in CxfRsInvoker* _[verified]_ -
{{CxfRsInvoker.java:~165}}: {{method.getReturnType() == Void.class}} is false
for {{void}} methods ({{void.class}}), so {{InOnly}} is never selected; a
{{void}} resource method's route result leaks back as a response body. Fix:
test {{Void.TYPE || Void.class}} (verify the MEP change before shipping).
# *Void.class confusion in SubResourceClassInvocationHandler* -
{{SubResourceClassInvocationHandler.java:~33}}: {{void}} methods fall into
{{findResourceConstructor(void.class)}} -> NPE instead of returning null. Fix:
{{returnType != Void.TYPE && returnType != Void.class}}.
# *Async http-API leaks the JAX-RS Response for InOnly exchanges* -
{{CxfRsProducer.java:~708-710}}: the sync path closes the {{Response}} for
non-out-capable exchanges; the async {{completed()}} returns without closing,
pinning connections under keep-alive. Fix: {{response.close()}} in the InOnly
branch.
# *Multi-valued Camel headers flattened via toString()* -
{{CxfHeaderHelper.java:~105}} (via
{{DefaultCxfRsBinding.bindCamelHeadersToRequestHeaders}}): a {{List}}-valued
header is serialized as the literal {{"[a, b]"}}. The sibling
{{propagateCamelToCxf}} handles {{List}} correctly. Fix: add each list element
to the multivalued map.
# *Inbound protocol headers keep only the first value* -
{{DefaultCxfRsBinding.java:~333}}; producer error headers
{{CxfRsProducer.java:~655}}: {{get(0)}} drops repeated headers (e.g. multiple
{{Set-Cookie}}) into {{CxfOperationException.headers}} and the consumer header
map. Fix: reuse {{convertCxfProtocolHeaderValues}}.
# *setProtocolHeaders NPE when CXF out message absent* -
{{DefaultCxfRsBinding.java:~127-146}}: the null-guard covers only the
{{putIfAbsent}}; the following {{getOutMessage().get(..)}} is unguarded
(oneway/fault paths). Also {{ObjectHelper.isEmpty(cxfExchange)}} tests
map-emptiness, not nullness. Fix: hoist a single out-message null check.
# *CxfConverter fallback NPEs on a Response with null entity* -
{{CxfConverter.java:~221-232}}: {{entity.getClass()}} with no null check; a
204/empty {{Response}} throws inside the type converter. Separately,
{{toStreamCache}} ({{~135}}) never closes the {{Response}} -> connection held
until GC. Fix: null-check entity -> return {{MISS_VALUE}}; close the
{{Response}} after caching.
h2. camel-cxf-transport
# *CamelConduit producer leak / use-after-stop race* -
{{CamelConduit.java:~77-84,108-117}}: the producer is created+started in the
constructor, stopped only in {{close()}}; an abandoned conduit leaks it, and an
in-flight {{asyncInvokeFromWorkQueue}} can call {{producer.process}} after
{{close()}} stopped it. Fix: guard against use-after-stop; consider lazy
producer acquisition.
# *asyncInvokeFromWorkQueue NPE when no fault observer* -
{{CamelOutputStream.java:~133-140}}: if both {{getFaultObserver()}} and
{{exchange.get(MessageObserver.class)}} are null, {{mo.onMessage}} NPEs on a
work-queue thread and loses the original exception; the chain is also cast to
{{PhaseInterceptorChain}} without a null check. Fix: null-check both.
# *getBasePath regex fallback is fragile* -
{{DefaultCxfMessageMapper.java:~149-159}}: the second {{replaceFirst}} can
never fire after the first; non-HTTP front endpoints ({{direct:}}, {{jms:}})
leave the raw Camel URI as the SOAP BASE_PATH, breaking {{convertPathInfo}}
path stripping. Fix: only rewrite when the URI is actually http(s).
h2. camel-cxf-spring-*
# *CAMEL-18528 graceful bus shutdown is dead code in the standard XML path* -
{{CxfSpringEndpoint.java:~285-299}}: {{enableSpringBusShutdownGracefully}} is
only reachable from {{getBus()}}'s {{bus == null}} branch, but
{{setApplicationContext}} always assigns the bus first, so it never runs on the
first lifecycle; in-flight SOAP calls still fail on abrupt bus shutdown - the
exact scenario CAMEL-18528 claims to fix.
# *enableSpringBusShutdownGracefully removes an arbitrary listener and spawns a
thread per event* - {{CxfSpringEndpoint.java:~310-359}}: keeps the last
matching {{SpringBus}} listener, so with multiple buses it can unhook a
different bus (leak) and double-fire this one; also starts {{new Thread()}} for
every {{ApplicationEvent}}. Fix: match by bus identity; only spawn for
{{ContextClosedEvent}}.
# *performInvocation not propagated to SpringJAXRSServerFactoryBean* -
{{SpringJAXRSServerFactoryBean.java:~119-133}}: the bean reads its own
always-false field, not the endpoint's, so interface-model resources aren't
filtered in the Spring variant. Fix: propagate {{isPerformInvocation()}} before
server creation.
# *SpringJAXRSServerFactoryBean missing the setProperties merge override* -
{{SpringJAXRSServerFactoryBean.java:~110-117}}: the client bean merges, the
server bean uses CXF's replace-semantics, so a {{<cxf:properties>}} element
wipes the {{NullFaultListener}} installed by {{skipFaultLogging="true"}}. Fix:
add the same merging override.
# *CxfRsSpringEndpoint hard-casts CamelContext to SpringCamelContext* -
{{CxfRsSpringEndpoint.java:~51}} (selection in
{{CxfRsComponent.java:~130-139}}): a camel-main/{{DefaultCamelContext}} app
with the module on the classpath gets a {{ClassCastException}} instead of
falling back to the default factory. Fix: gate the Spring factory on
{{instanceof SpringCamelContext}}.
----
Note: two additional security-flavoured findings from the same review (an
inbound header-filter prefix gap and a transport header-map bypass) are being
handled through the ASF private security process and are intentionally not
listed here.
----
_Filed by Claude Code (Claude Fable) on behalf of Federico Mariani (GitHub:
Croway). Findings from an AI-assisted code review of the camel-cxf component
family; each item was verified against the current source and git history.
Items marked *[reproducer attached]* include a failing JUnit test that
demonstrates the defect._
--
This message was sent by Atlassian Jira
(v8.20.10#820010)