[
https://issues.apache.org/jira/browse/CAMEL-24132?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18096830#comment-18096830
]
Claus Ibsen commented on CAMEL-24132:
-------------------------------------
Fixed via https://github.com/apache/camel/pull/24794
> camel-jpa: medium-severity findings from July 2026 component review (umbrella)
> ------------------------------------------------------------------------------
>
> Key: CAMEL-24132
> URL: https://issues.apache.org/jira/browse/CAMEL-24132
> Project: Camel
> Issue Type: Bug
> Components: camel-jpa
> Reporter: Federico Mariani
> Assignee: Claus Ibsen
> Priority: Minor
> Fix For: 4.22.0
>
>
> h3. Overview
> This is an umbrella issue tracking 7 medium-severity findings from a broader
> code review of {{camel-jpa}} (July 2026), grouped here rather than filed
> individually since none is independently critical. High-severity findings
> from the same review were filed separately as standalone issues.
> h3. M1 -- JpaPollingConsumer.receiveNoWait() can block indefinitely
> JpaPollingConsumer.java:186-189 implements {{receiveNoWait()}} by simply
> delegating to {{receive()}}, which runs a full transaction and acquires a
> {{PESSIMISTIC_WRITE}} lock by default -- it can block on row locks for an
> unbounded time. This violates the {{PollingConsumer}} contract that
> {{receiveNoWait()}} returns immediately. At minimum it should apply a NOWAIT
> lock hint (or no lock) rather than reusing {{receive()}} as-is.
> h3. M2 -- receive(timeout) never cancels the background task on timeout
> JpaPollingConsumer.java:192-212: on {{TimeoutException}}, the method returns
> {{null}} but never calls {{future.cancel(true)}}. The submitted task keeps
> running in the background -- holding/awaiting DB locks -- and, once it
> eventually completes, leaks its {{EntityManager}} (see the related EM-leak
> issue) and its {{Exchange}}. Under repeated timeouts (e.g. {{pollEnrich}}
> against a locked table with a short timeout), abandoned tasks accumulate in
> the shared, bounded thread pool, and later polls start timing out purely from
> queueing.
> h3. M3 -- JpaPollingConsumer + nativeQuery + default consumeLockEntity always
> fails
> JpaPollingConsumer.java:143-145 calls {{innerQuery.setLockMode(...)}}
> whenever {{consumeLockEntity}} is {{true}} (the default). Per the JPA spec,
> {{Query.setLockMode}} throws {{IllegalStateException}} for anything other
> than a JPQL SELECT / CriteriaQuery -- i.e. for every native query (and for
> update-style named queries). {{pollEnrich("jpa:X?nativeQuery=...")}} can
> never succeed without the caller explicitly setting
> {{consumeLockEntity=false}}. The call should be guarded (skipped for native
> queries), or the requirement should be documented prominently.
> h3. M4 -- JpaMessageIdRepository.add() turns a concurrent-insert race into a
> failed exchange instead of a duplicate signal
> JpaMessageIdRepository.java:102-111 is check-then-insert.
> {{MessageProcessed}} has a unique constraint on {{(processorName,
> messageId)}}, so when two exchanges race on the same id (parallel threads or
> a clustered deployment sharing the table), the loser hits a constraint
> violation at {{flush()}}, which the {{catch}} block wraps and rethrows as a
> {{PersistenceException}} -- *failing the exchange* -- instead of treating it
> as "duplicate detected" and returning {{false}}. For a repository whose
> entire purpose is cluster-safe idempotency, the constraint-violation race
> should be caught and mapped to {{return false}}.
> h3. M5 -- the CAMEL-22534 parallel-EntityManager fix only covers the Splitter
> CAMEL-22534 made the Splitter strip the {{CamelEntityManager}} exchange
> property from parallel sub-exchange copies.
> {{multicast(parallelProcessing)}}, {{recipientList(parallel)}} and
> {{wireTap}} still copy exchange properties by default, so parallel branches
> through those EIPs can share the same non-thread-safe {{HashMap<String,
> EntityManager>}} ({{JpaHelper.getEntityManagerMap}}) *and* the same
> {{EntityManager}} instances across threads -- both concurrent EM use and map
> corruption are possible. Consider moving the property-strip into a shared
> place (e.g. {{MulticastProcessor}}), or making the JPA helper's map
> thread-safe / per-thread.
> h3. M6 -- JpaProducer.isUseExecuteUpdate() misclassifies legitimate SELECTs
> JpaProducer.java:145-164 decides between {{executeUpdate()}} and
> {{getResultList()}} by testing whether the raw query string starts with
> {{"select"}} (case-insensitive, offset 0, no trimming). A query with leading
> whitespace/newline, a native CTE ({{WITH x AS (...) SELECT ...}}), or a
> parenthesized select is misclassified as an update and routed to
> {{executeUpdate()}}, which the JPA provider rejects. The string should be
> trimmed first, and {{WITH}} should also be recognized as a select-style query
> (or, more robustly, only auto-detect the update keywords
> {{insert|update|delete}} and default to select otherwise).
> h3. Note
> A 7th medium finding from the same review (header-supplied query parameters
> being auto-evaluated as a Simple expression) is *not* included here: it falls
> under the project's documented in-scope security vulnerability classes
> (expression injection where the framework itself evaluates untrusted input)
> and is being routed through the private SECURITY.md disclosure process
> instead of a public issue.
> See also the four related high-severity issues filed from the same review.
> _Claude Code on behalf of Croway_
--
This message was sent by Atlassian Jira
(v8.20.10#820010)