[ 
https://issues.apache.org/jira/browse/CAMEL-24164?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Claus Ibsen resolved CAMEL-24164.
---------------------------------
    Resolution: Fixed

> camel-jaxb - CamelJaxbPartClass header permanently mutates the shared data 
> format (state pollution + data race)
> ---------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-24164
>                 URL: https://issues.apache.org/jira/browse/CAMEL-24164
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-jaxb
>            Reporter: Federico Mariani
>            Assignee: Federico Mariani
>            Priority: Major
>              Labels: ai-assisted-review, dataformat
>             Fix For: 4.22.0
>
>         Attachments: JaxbPartClassHeaderStatePollutionIssueTest.java
>
>
> *Severity:* High (correctness + security-adjacent)
> *Affects:* 4.x (predates the 2020 reifier split)
> h3. Problem
> {{JaxbDataFormat}} unmarshal and marshal assign the header-derived part class 
> into the *instance field*:
> {code:java}
> partClass = 
> camelContext.getClassResolver().resolveMandatoryClass(partClassFromHeader, 
> ...);
> {code}
> A {{DataFormat}} is shared across all exchanges of a route step, so:
> * *Sticky*: after any one exchange carries the {{CamelJaxbPartClass}} header, 
> {{partClass != null}} forever — every subsequent header-less exchange is 
> silently unmarshalled as a partial {{JAXBElement}} bound to the leaked class.
> * *Race*: two concurrent exchanges with different {{CamelJaxbPartClass}} 
> headers can unmarshal into each other's class.
> h3. Security note
> {{CamelJaxbPartClass}}/{{CamelJaxbPartNamespace}} are plain message headers. 
> On a consumer that does not filter {{Camel*}} headers, an untrusted sender 
> can pick the unmarshal target class and, via the stickiness, poison all later 
> exchanges (header-abuse family, CVE-2025-27636 lineage). Mitigated by a 
> compliant default {{HeaderFilterStrategy}}, but the persistence makes any 
> single leak durable.
> (XXE was reviewed and is not affected — all unmarshal paths go through the 
> hardened {{StaxConverter}}.)
> h3. Failure scenario
> Route {{from(direct).unmarshal(jaxb)}} with no partClass configured. Exchange 
> 1 arrives with header {{CamelJaxbPartClass=Partial}} -> unmarshals as 
> {{Partial}} (fine). Exchange 2 (a normal {{<purchaseOrder>}} document, *no 
> header*) -> unmarshalled as {{Partial}} instead of {{PurchaseOrder}}.
> h3. Suggested fix
> Resolve the header-derived class into a *local variable* per call ({{Class<?> 
> effectivePartClass = partClassFromHeader != null ? resolve(...) : 
> this.partClass;}}); never assign the instance field from exchange data.
> h3. Reproducer
> Attached {{JaxbPartClassHeaderStatePollutionIssueTest.java}}: 
> single-threaded, deterministic; exchange 2's body leaks to 
> {{org.apache.camel.example.Partial}} (expected {{PurchaseOrder}}). RED on 
> current code.
> ----
> _Reported by Claude Code on behalf of Federico Mariani (Croway). A failing 
> JUnit reproducer (confirmed RED on 4.22.0-SNAPSHOT) is attached._



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to