This is an automated email from the ASF dual-hosted git repository.
oscerd pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 6bbc943e342f docs: update the security model against the 2026 advisory
batch (#25699)
6bbc943e342f is described below
commit 6bbc943e342f9db5e906a974b0ebfdf7cdddf56a
Author: Andrea Cosentino <[email protected]>
AuthorDate: Tue Aug 25 15:08:07 2026 +0200
docs: update the security model against the 2026 advisory batch (#25699)
Reconciles the security model with the published 2026 advisories.
Twenty-five
published CVEs were not reflected; rather than appending IDs to the existing
class lists, this captures the eight places where an advisory showed the
model
was wrong or too narrow - cases where a triager following the current text
would have closed a real finding.
Trust and adversary model
Three input sources are now stated as attacker-controlled. The adversary
model
only covered a message arriving on a transport a consumer reads, so nothing
placed these inside it:
* names and metadata a remote store reports back (CVE-2026-66906,
CVE-2026-60093, CVE-2026-66907 - remote object names traversing out of the
configured download directory);
* the output of an LLM, including tool-call field names and arguments
(CVE-2026-49042);
* transport metadata that is not a message header - query parameters, path
segments (CVE-2026-55993).
A Roles row is added for the far side of a component: trusted to hold the
route's data, untrusted for what it returns. The aggregation-repository
limitation is scoped to state the route itself wrote and reads back, so it
no
longer reads as covering names other principals put in the store.
Camel-header / bean-dispatch class
The model drew one line - Camel* is the framework's job, everything else is
route-author responsibility. That discharges reports it should not, so the
class is reorganised around three refinements:
* A control header is defined by what it does, not by its prefix: a header
that selects a target, an operation, or the transport and its credentials
is
internal however it is spelled (CVE-2026-71300, CVE-2026-48204,
CVE-2026-49097, CVE-2026-46592, CVE-2026-46587, CVE-2026-46588,
CVE-2026-46453, CVE-2026-46584, CVE-2026-49086). Semantic headers - those
a
component reads as payload data - remain pass-through by contract.
* Every inbound mapping site is in scope, not only the consumer: data
formats
(CVE-2026-59230, CAMEL-24419), structured content modes (CVE-2026-63621)
and
transport-metadata mapping (CVE-2026-55993) populate the same header map.
* A filter that is never consulted is not a filter (CVE-2026-78329, where
the
strategy was constructed and immediately overwritten so CAMEL-23588 had
been
inert since it shipped; CAMEL-24412, a case-insensitive check behind a
case-sensitive guard).
New in-scope class
Argument injection into an external process Camel launches (CVE-2026-40047).
The properties table already claimed untrusted data is never turned into
executed code or OS commands, but no class carried the mechanism.
Authentication and authorization
Two sub-rules, each now behind more than one advisory: an unconfigured check
must fail closed rather than drop out of the validation chain
(CVE-2026-66908,
CVE-2026-53913, CAMEL-24411), and the authorization decision must be
computed
from the same normalized value as dispatch (CVE-2026-40022, CAMEL-24412).
Deserialization
An under-strength filter is a case in its own right (CVE-2026-42527).
Records
the JEP-290 filter CamelObjectInputStream applies by default since 4.22
(CAMEL-24296) as a floor beneath the per-component rules, and notes the
indirect route through a third-party API that delegates to JDK
serialization,
which a grep for `new ObjectInputStream(` does not find.
Triage
An incomplete fix is a new finding rather than a re-opening, in three
shapes:
not-all-call-sites (CAMEL-24413, CAMEL-24420), under-strength mitigation
(CVE-2026-42527), alternate route to the same sink (CVE-2026-43866,
CVE-2026-46591). VALID-HARDENING no longer says "typically without a CVE" -
CVE-2026-56140 is a hardening change that carries an advisory.
Scope
States which artifacts the model covers. The sibling subprojects ship on
their
own release trains with their own deployment surfaces; CVE-2026-45760 is a
Camel K finding whose entire mechanism lives outside this model.
Known limitations, Known non-findings, the disclaimed properties, the
false-friend list, deployment hardening and the component-author guidance
are
updated to match, and security-model.yaml is regenerated.
Signed-off-by: Andrea Cosentino <[email protected]>
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
---
.../modules/ROOT/attachments/security-model.yaml | 54 ++-
.../modules/ROOT/pages/security-model.adoc | 394 +++++++++++++++++++--
2 files changed, 411 insertions(+), 37 deletions(-)
diff --git a/docs/user-manual/modules/ROOT/attachments/security-model.yaml
b/docs/user-manual/modules/ROOT/attachments/security-model.yaml
index 171dda176592..19be613b5c4c 100644
--- a/docs/user-manual/modules/ROOT/attachments/security-model.yaml
+++ b/docs/user-manual/modules/ROOT/attachments/security-model.yaml
@@ -43,14 +43,20 @@ roles:
- role: external_message_senders
trust: untrusted
note: "Primary adversary model - body, headers, attachments, transport
metadata."
+ - role: component_far_side # remote services, object stores,
brokers, AI models
+ trust: trusted_to_hold_data_untrusted_for_what_they_return
+ note: "Object/blob names, listing entries and LLM output are
attacker-influenced."
trust_boundary:
trusted: "the route plus everything the operator configured"
untrusted: "the data flowing through the route (Exchange body, headers,
attachments)"
adversary_in_scope:
- controls: [message_body, message_headers, attachments, transport_metadata]
- goals: [rce, endpoint_or_bean_redirect, unsafe_deserialization, xxe_ssrf,
path_traversal, auth_bypass, secret_disclosure, backend_query_injection]
+ controls: [message_body, message_headers, attachments, transport_metadata,
+ remote_store_object_names_and_metadata, #
CVE-2026-66906/60093/66907
+ llm_output_and_tool_call_arguments, # CVE-2026-49042
+ query_parameters_and_path_segments] # CVE-2026-55993
+ goals: [rce, endpoint_or_bean_redirect, unsafe_deserialization, xxe_ssrf,
path_traversal, auth_bypass, secret_disclosure, backend_query_injection,
external_process_argument_injection]
adversary_out_of_scope:
- route_authors
- deployment_operators
@@ -73,6 +79,9 @@ component_families:
in_scope: false
- family: examples_and_samples
in_scope: false
+ - family: sibling_subprojects # Camel K, Camel Quarkus, Camel Spring
Boot, Camel Kafka Connector, Camel Karaf
+ in_scope: false
+ reason: "own release trains and deployment surfaces; core routing
behaviour inherits this model (e.g. CVE-2026-45760 is Camel K)"
config_variants:
profiles:
@@ -119,10 +128,10 @@ config_variants:
properties_provided:
# id, violation symptom, indicative severity tier
- id: no_untrusted_code_execution
- symptom: "deserialization gadget / bean-method-command dispatch /
expression eval not requested by route"
+ symptom: "deserialization gadget / bean-method-command dispatch /
expression eval not requested by route / splice into external-process argv"
severity: critical
- id: no_untrusted_endpoint_redirect
- symptom: "wire-injected internal header changes dispatch target
(CamelBeanMethodName, CamelHttpUri, ...)"
+ symptom: "wire-injected control header changes dispatch target, operation,
or transport+credentials - inside the namespace (CamelBeanMethodName,
CamelHttpUri, ...) or outside it (websocket.connectionKey, gridfs.*,
irc.sendTo, operationName, mail.smtp.*)"
severity: critical
- id: no_arbitrary_deserialization
symptom: "attacker-chosen types instantiated via
ObjectInputStream/XStream/Hessian/polymorphic-Jackson without filter"
@@ -131,10 +140,10 @@ properties_provided:
symptom: "XML/XSLT/XSD/XPath parse of attacker input reads file / SSRF /
fetches remote DTD/stylesheet"
severity: high
- id: no_path_escape
- symptom: "file/mail/ftp path escapes configured root via ../ or absolute
header"
+ symptom: "file/mail/ftp/object-store path escapes configured root via ../
or absolute name, whether supplied in a header or reported back by the remote
store"
severity: high
- id: auth_components_enforce
- symptom: "request served without valid token / unvalidated
issuer-audience-signature / uncovered subpath"
+ symptom: "request served without valid token / unvalidated
issuer-audience-signature / uncovered subpath / check silently skipped because
its option was unset / authorization computed from a differently-normalized
value than dispatch"
severity: critical
- id: no_secret_or_state_disclosure
symptom: "secrets/bodies/config reach a log (INFO/WARN/ERROR), event,
world-readable file, or HTTP response"
@@ -155,7 +164,7 @@ core_router_engine_invariants:
properties_not_provided:
- jvm_or_route_sandboxing
- availability_under_attacker_volume # DoS / resource exhaustion
- - application_level_header_sanitisation # only Camel* namespace is
filtered
+ - application_level_semantic_header_sanitisation # payload-data headers
only; a component's own control headers ARE in scope whatever they are named
- transitive_dependency_cve_shielding
- production_guarantees_under_dev_or_test_profile
- information_hiding_at_debug_or_trace_log_levels
@@ -164,27 +173,42 @@ properties_not_provided:
false_friends:
- "DefaultHeaderFilterStrategy filters the internal Camel* namespace only,
not application headers"
- - "removeHeaders(Camel*) strips internal-dispatch headers, not every
untrusted header"
+ - "removeHeaders(Camel*) strips internal-dispatch headers, not every
untrusted header, and does not match control headers spelled outside the
namespace"
+ - "a HeaderFilterStrategy that is constructed but overwritten, or applied on
one entry point only, filters nothing on the path that matters (CVE-2026-78329)"
- "security policy framework is a startup linter, not a runtime sandbox"
- "component deprecation is not a security boundary"
- "TLS-by-default is not peer authentication"
in_scope_classes:
- id: unsafe_deserialization
- examples: [CVE-2026-40860, CVE-2026-43866, CVE-2026-40859, CVE-2026-43865,
CVE-2026-46590, CVE-2026-40473]
+ examples: [CVE-2026-40860, CVE-2026-43866, CVE-2026-40859, CVE-2026-43865,
CVE-2026-46590, CVE-2026-40473, CVE-2026-42527]
+ mitigation_default: "CamelObjectInputStream installs a JEP-290 filter by
default since 4.22 (CAMEL-24296), honouring jdk.serialFilter when set"
+ note: "an under-strength filter (CVE-2026-42527) and an indirect route via
a third-party JDK-serialization API both fall in this class"
- id: xxe_and_remote_resource_resolution
examples: [CVE-2014-0002, CVE-2018-8027, CVE-2019-0188]
- id: expression_or_template_injection
examples: [CVE-2013-4330, CVE-2020-11994]
- id: path_traversal
- examples: [CVE-2018-8041, CVE-2019-0194]
+ examples: [CVE-2018-8041, CVE-2019-0194, CVE-2026-66906, CVE-2026-60093,
CVE-2026-66907]
+ note: "the escaping name may be reported back by the remote store, not
supplied in a message"
- id: ssrf_or_remote_fetch_on_parse
examples: [CVE-2017-5643]
- id: camel_header_bean_dispatch_abuse
examples: [CVE-2025-27636, CVE-2026-40453, CVE-2026-46456, CVE-2026-46457,
CVE-2026-46726, CVE-2026-48205, CVE-2026-48206, CVE-2026-49098, CVE-2026-49099]
mitigation_default: "DefaultHeaderFilterStrategy blocks Camel* by default
since 4.21 (CAMEL-23543)"
+ control_header_test: "a header is in scope when it selects a target, an
operation, or the transport and its credentials - regardless of prefix"
+ control_headers_outside_namespace: [CVE-2026-71300, CVE-2026-48204,
CVE-2026-49097, CVE-2026-46592, CVE-2026-46587, CVE-2026-46588, CVE-2026-46453,
CVE-2026-46584, CVE-2026-49086]
+ inbound_mapping_sites: [consumer, data_format_unmarshal,
structured_content_mode, transport_metadata]
+ mapping_site_examples: [CVE-2026-59230, CVE-2026-63621, CVE-2026-55993,
CVE-2026-55994, CVE-2026-46454, CVE-2026-49042]
+ inert_filter_examples: [CVE-2026-78329]
+ - id: argument_injection_into_external_process
+ examples: [CVE-2026-40047]
+ note: "framework builds the argv on the route author's behalf;
route-author exec is out of scope"
- id: auth_or_authz_bypass
- examples: [CVE-2026-23552, CVE-2026-40022, CVE-2026-46455, CVE-2026-53913]
+ examples: [CVE-2026-23552, CVE-2026-40022, CVE-2026-46455, CVE-2026-53913,
CVE-2026-66908]
+ sub_rules:
+ - "an unconfigured check must fail closed, never silently drop out of
the chain (CVE-2026-66908, CVE-2026-53913, CAMEL-24411)"
+ - "authorization and dispatch must be computed from the same normalized
value (CVE-2026-40022, CAMEL-24412)"
- id: information_disclosure
examples: [CVE-2023-34442, CVE-2024-22371, CVE-2026-49365, CVE-2026-56139]
- id: insecure_defaults
@@ -197,7 +221,7 @@ known_non_findings:
- "route-author simple/xpath/groovy/jexl/mvel evaluation"
- "route-author .bean/.process/Runtime.exec/Class reference"
- "Camel* header controls dispatch (intentional contract)"
- - "application-level header (To/Subject/HTTP X-/JMS/AMQP/MQTT/CoAP/Kafka)
not stripped"
+ - "application-level SEMANTIC header (To/Subject/HTTP
X-/JMS/AMQP/MQTT/CoAP/Kafka) not stripped - NOT applicable when the header
selects a target, an operation, or the transport and its credentials; see
control_header_test"
- "DefaultHeaderFilterStrategy case bypass (it is case-insensitive by
default)"
- "management surface (dev console, backlog debugger, tracer, JMX, jolokia)
exposes code/state"
- "finding only under camel.main.profile=dev or test"
@@ -206,10 +230,14 @@ known_non_findings:
- "deprecated component still ships and has a CVE"
- "documented opt-in option enables unsafe behaviour"
- "finding in core/camel-* where every core invariant held"
+ # not a non-finding, recorded here so triage does not mistake it for one:
+ # "the component declares a HeaderFilterStrategy" is not evidence the
strategy runs on the live path
+
+incomplete_fix_rule: "residue of a published advisory is triaged from scratch
and, if VALID, gets its own advisory; shapes: not-all-call-sites
(CAMEL-24413/24420), under-strength mitigation (CVE-2026-42527), alternate
route to the same sink (CVE-2026-43866, CVE-2026-46591)"
dispositions:
- VALID
- - VALID-HARDENING
+ - VALID-HARDENING # may still carry an advisory, e.g. CVE-2026-56140
- "OUT-OF-MODEL: trusted-input"
- "OUT-OF-MODEL: adversary-not-in-scope"
- "OUT-OF-MODEL: unsupported-component"
diff --git a/docs/user-manual/modules/ROOT/pages/security-model.adoc
b/docs/user-manual/modules/ROOT/pages/security-model.adoc
index 4c7f867dbeea..83f8034311d8 100644
--- a/docs/user-manual/modules/ROOT/pages/security-model.adoc
+++ b/docs/user-manual/modules/ROOT/pages/security-model.adoc
@@ -73,6 +73,16 @@ application, not a multi-tenant managed service. Its trust
model reflects that.
primary attacker model. The framework must not turn an untrusted message into
code execution, file read, request forgery or authentication bypass on its
own.
+
+| The far side of a component - the remote services, object stores, brokers and
+ AI models a route talks to
+| Trusted to *hold* the route's data; untrusted for what they *return*
+| Return payloads, object and blob names, remote file names, listing entries
+ and other metadata, and - for the AI components - generated text and
+ tool-call arguments. The operator chose to talk to these services, so the
+ connection is trusted; the strings they hand back are attacker-influenced
+ whenever a wider set of principals can write to the store or shape the
+ prompt. See _Adversary model_.
|===
=== Trust boundaries
@@ -104,6 +114,38 @@ framework's own machinery - expression languages, type
converters, the
property-placeholder and bean-reference resolution, and any default parser
configuration used by a consumer or data format.
+*Three further inputs count as attacker-controlled* even though they do not
+arrive as a message on the transport a consumer reads. Each has produced
+accepted advisories, and each is easy to mistake for trusted data because it
+reaches Camel from a service the operator configured rather than from the
+wire:
+
+* *Names and metadata a remote backing service reports back.* Object keys,
+ blob and bucket names, remote file names and listing entries are chosen by
+ whoever can write to that store, which is routinely a wider set of
+ principals than the peers who can reach the route. A component that builds a
+ local path, a command argument or a header out of such a name is handling
+ untrusted input (CVE-2026-60093 `camel-azure-storage-datalake`,
+ CVE-2026-66906 `camel-azure-storage-blob`, CVE-2026-66907
+ `camel-google-storage` - remote object names traversing out of the
+ configured download directory). This is distinct from the *contents* of a
+ state store the operator provisioned for the route's own use, which the
+ framework does assume are trusted; see the aggregation-repository bullet
+ under _Known limitations_.
+* *The output of a large language model.* In the AI components a model's
+ reply - including the field names and arguments of a tool call - is
+ generated from a prompt and a retrieved context that an external party can
+ often influence. Model output is untrusted input, not a trusted control
+ channel, and a component that maps it into the `Exchange` header map or into
+ a dispatch decision is bound by the same rules as any other inbound mapping
+ site (CVE-2026-49042 `camel-langchain4j-tools`, where unfiltered tool-call
+ argument names became arbitrary `Exchange` headers).
+* *Transport metadata that is not a message header.* Query parameters, path
+ segments, subscription and topic names and connection attributes reach the
+ `Exchange` through the same mapping code as headers do (CVE-2026-55993
+ `camel-atmosphere-websocket`, WebSocket query parameters mapped without a
+ `HeaderFilterStrategy`).
+
*What the attacker is trying to do:* break one of the properties listed in
_Security properties and violation severity_ or _Core router-engine
invariants_ below - turn untrusted input into code execution, an arbitrary
@@ -152,6 +194,19 @@ A report is in scope when it demonstrates that the
framework, in a default or
reasonably-expected configuration, lets untrusted input cross a trust boundary
that the model says it should not cross.
+*Which artifacts this model covers.* This document describes the artifacts
+released from the `apache/camel` repository - `camel-core`, the components,
+the DSLs and the Camel CLI. The sibling subprojects ship on their own release
+trains and are triaged against their own scope: Camel K, Camel Quarkus, Camel
+Spring Boot, Camel Kafka Connector and Camel Karaf. They inherit this trust
+model for the core routing behaviour they embed, but each adds a deployment
+surface with its own roles and adversaries that this page does not describe -
+CVE-2026-45760, a cross-namespace build "deputy" attack in Camel K, is an
+example of a finding whose entire mechanism (Kubernetes namespaces, operator
+RBAC) lives outside this model. A report against one of those subprojects is
+triaged by the same PMC on the same private list, but against the
+subproject's surface, not this page's.
+
=== Security properties and violation severity
The trust-boundary statement above commits the framework to a small set of
@@ -169,11 +224,11 @@ which protective property it breaks.
| Indicative severity
| Untrusted data is never turned into executed code or OS commands
-| A crafted message, header or attachment causes a deserialisation gadget
chain, a bean / method / command dispatch, or an expression/template evaluation
the route author never requested
+| A crafted message, header or attachment causes a deserialisation gadget
chain, a bean / method / command dispatch, an expression/template evaluation
the route author never requested, or is spliced into the argument vector of an
external process the component launches
| Critical (CVSS 9.0-10.0)
| Untrusted data cannot redirect the route to a different endpoint, bean,
method or command
-| An internal header injected from the wire (`CamelBeanMethodName`,
`CamelExecCommandExecutable`, `CamelHttpUri`, `CamelJmsDestinationName`, ...)
changes where the exchange is dispatched
+| A control header injected from the wire changes where the exchange is
dispatched, which operation runs, or which transport and credentials are used -
whether it is spelled inside the internal namespace (`CamelBeanMethodName`,
`CamelExecCommandExecutable`, `CamelHttpUri`, `CamelJmsDestinationName`, ...)
or outside it (`websocket.connectionKey`, `gridfs.*`, `irc.sendTo`,
`operationName`, `mail.smtp.*`, ...)
| Critical (CVSS 9.0-9.8)
| Untrusted data is never deserialised into arbitrary Java types
@@ -185,11 +240,11 @@ which protective property it breaks.
| High (CVSS 7.5-8.6); Critical if it yields RCE or credential theft
| Untrusted file names or URI components cannot escape the configured root
-| A file / mail / FTP consumer or producer reads or writes a path outside the
configured directory via `../` or an absolute path supplied in a header
+| A file / mail / FTP / object-store consumer or producer reads or writes a
path outside the configured directory via `../` or an absolute path, whether
that name arrived in a header or was reported back by the remote store
| High (CVSS 7.5-8.8)
| Components that advertise authentication or authorization actually enforce it
-| A request is served without a valid token, with an unvalidated issuer /
audience / signature, or on a sub-path the auth handler was assumed to cover
+| A request is served without a valid token, with an unvalidated issuer /
audience / signature, on a sub-path the auth handler was assumed to cover,
because a check was silently skipped when its option was left unconfigured, or
because the authorization decision was computed from a differently-normalized
value than the dispatch decision
| Critical (CVSS 9.0-9.8)
| Secrets and internal Exchange state are not disclosed
@@ -308,8 +363,13 @@ routed to "X was not built to do Y" rather than re-argued
case by case.
arbitrary HTTP header names; JMS properties; AMQP, MQTT, CoAP and Kafka
headers - are passed through intentionally. Sanitising them against an
untrusted upstream is the route author's responsibility at the trust
- boundary (`removeHeaders`, normalisation, allow-listing). See the third
- bullet under _Known limitations_.
+ boundary (`removeHeaders`, normalisation, allow-listing). This disclaimer
+ covers headers a component reads as *payload data*; it does not cover a
+ component's own *control* headers - those that select a target, an
+ operation, or the transport and its credentials - which are the framework's
+ responsibility to filter whatever they are named. See the third bullet under
+ _Known limitations_ and the control-header definition under the Camel-header
+ class in _In-scope vulnerability classes_.
* *No shield against transitive-dependency CVEs.* A CVE in a JAR Camel
pulls in is the upstream project's vulnerability; Camel fixes CVEs in
Camel code, not in third-party JARs. Camel may upgrade the dependency
@@ -367,6 +427,12 @@ the misunderstanding can be closed against the correct
contract.
hygiene against the internal-header dispatch class (see _Deployment
hardening_), and it is necessary; it is not, on its own, sufficient
to sanitise the application headers a downstream component will trust.
+ It also does not match a control header spelled outside the namespace -
+ `websocket.connectionKey`, `gridfs.*`, `irc.sendTo`, `operationName`,
+ `mail.smtp.*`. Those are the framework's responsibility to filter and
+ have been fixed as advisories where they were reachable, but a route
+ running against a release that predates the relevant fix needs the
+ namespace stripped explicitly as well.
* *The security policy enforcement framework is a configuration linter,
not a runtime sandbox.* The four categories (`secret`, `insecure:ssl`,
`insecure:serialization`, `insecure:dev`) detect insecure configuration
@@ -433,6 +499,20 @@ Historical examples:
* CVE-2026-46590, CVE-2026-43867 (`camel-pqc`) - HashiCorp Vault and AWS
Secrets Manager key-lifecycle managers deserialising persisted key metadata
with `ObjectInputStream` (a follow-on to CVE-2026-40048).
+* CVE-2026-42527 - the *filter itself* being too permissive: the default
+ `ObjectInputFilter` pattern admitted `java.net.**` and so allowed
+ DNS-based information disclosure. A mitigation that is present but
+ under-strength falls in this class in its own right; see the incomplete-fix
+ note under _Triage dispositions_.
+
+Since 4.22 (CAMEL-24296) `CamelObjectInputStream` installs a JEP-290
+`ObjectInputFilter` by default - honouring a JVM-wide `jdk.serialFilter` when
+the operator has set one, and otherwise applying Camel's own allow-list. This
+is defence in depth beneath the per-component rules above, not a replacement
+for them: it constrains the streams that pass through that class, and a
+component that constructs a raw `ObjectInputStream`, or that reaches JDK
+serialisation indirectly through a third-party serializer API, is still
+responsible for its own filter.
==== XML external entity (XXE) and remote DTD/stylesheet resolution
@@ -470,6 +550,20 @@ component navigate outside the configured root directory.
Historical examples: CVE-2018-8041 (`camel-mail`), CVE-2019-0194
(`camel-file`).
+The name does not have to arrive in a message. A cluster of 2026 advisories
+came from *download* paths that built a local target out of a name the remote
+store reported back - CVE-2026-66906 (`camel-azure-storage-blob`,
+`downloadBlobToFile`), CVE-2026-60093 (`camel-azure-storage-datalake`,
+`downloadToFile`) and CVE-2026-66907 (`camel-google-storage`, where
+`downloadFileName` was evaluated with the `${file:name}` token, which returns
+the remote name verbatim, rather than `${file:onlyname}`, which strips the
+path). In each case the component joined the configured directory with the
+remote name and passed the result to the SDK with no lexical normalization and
+no containment check. Object and blob names are attacker-influenced whenever a
+principal who can write to the store is outside the route's trust boundary
+(see _Adversary model_), so a download target must be normalized and verified
+to resolve inside the configured directory before it is used.
+
==== SSRF or remote-resource fetch triggered by parsing
Any parser that resolves a URL or DTD reference from untrusted input as part of
@@ -479,12 +573,12 @@ Historical example: CVE-2017-5643 (Validation component
fetching remote DTDs).
==== Camel-header / bean-dispatch abuse via untrusted input
-Camel uses internal headers - `CamelBeanMethodName`, `CamelFileName`,
+Camel uses headers - `CamelBeanMethodName`, `CamelFileName`,
`CamelExecCommandExecutable`, `CamelJmsDestinationName`,
`CamelHttpUri`, `CamelJacksonUnmarshalType` and others - to drive component
-behaviour. Any consumer that maps untrusted input into the `Exchange` header
-map without a strict, case-insensitive `HeaderFilterStrategy` becomes an
-injection vector for these headers.
+behaviour. Any code that maps untrusted input into the `Exchange` header map
+without a strict, case-insensitive `HeaderFilterStrategy` becomes an injection
+vector for these headers.
Historical examples: CVE-2025-27636, CVE-2025-29891 (default HTTP
`HeaderFilterStrategy` bypass), CVE-2025-30177 (`camel-undertow` inbound
@@ -502,6 +596,87 @@ motivated centralising the default `Camel*` filter in
`DefaultHeaderFilterStrategy` (CAMEL-23543, Camel 4.21) so consumers and
producers block the internal namespace without per-component boilerplate.
+Three refinements decide how this class is actually applied: which headers
+count, which code sites count, and whether the filter that is supposed to be
+in the way is really in the way. Each was learned from an advisory where the
+narrower reading would have wrongly closed a real finding.
+
+*A control header is defined by what it does, not by its prefix.* The
+framework's automatic filter covers the `Camel*` namespace, but the property
+this class protects is that untrusted input must not steer the exchange - and
+a component is free to name a steering header anything it likes. A header is a
+*control* header, and belongs in the component's inbound filter set whatever
+it is called, when it selects any of:
+
+* *the target* - which peer, channel, destination, topic or recipient the
+ message goes to (CVE-2026-71300 `camel-atmosphere-websocket`,
+ `websocket.connectionKey` / `.list` / `sendToAll`; CVE-2026-49097
+ `camel-irc`, `irc.sendTo`);
+* *the operation* - which method, verb or command the component performs
+ (CVE-2026-48204 `camel-mongodb-gridfs`, `gridfs.*`, including file deletion;
+ CVE-2026-46592 `camel-cxf`, `operationName` / `operationNamespace`;
+ CVE-2026-46587 `camel-couchbase`, CVE-2026-46588 `camel-couchdb`,
+ CVE-2026-46453 `camel-elasticsearch-rest-client`);
+* *the transport or its credentials* - which host, protocol, TLS posture or
+ authentication the component uses (CVE-2026-46584 `camel-mail`, where
+ attacker-supplied `mail.smtp.*` / `mail.smtps.*` headers were applied as
+ JavaMail session properties, weakening SMTP transport security and, before
+ 4.19.0, redirecting the connection and disclosing the configured
+ credentials).
+
+By contrast a *semantic* header is one the component reads as payload data -
+`To`, `Cc`, `Subject`, an HTTP `X-` header, a JMS property. Those are
+pass-through by contract and sanitising them is route-author work (see
+_Known limitations_). The two categories are not distinguished by spelling,
+so "the header has no `Camel` prefix" does not by itself discharge a report;
+the triager has to ask what the header does. A consumer that copies untrusted
+input into a header the *producer* side treats as control input is the same
+finding even though the two sides sit in different components
+(CVE-2026-49086 `camel-dapr`, where the Pub/Sub consumer copied the inbound
+CloudEvent's pub/sub name and topic into producer-direction routing headers,
+letting anyone who could publish to the subscribed topic redirect the
+re-published message).
+
+*Every inbound mapping site is in scope, not only the consumer.* The
+`Exchange` header map is populated from more than one place, and each place
+needs an effective strategy:
+
+* *Consumers*, mapping transport headers - the original shape.
+* *Data formats and unmarshallers*, mapping headers found inside the payload
+ they decode. CVE-2026-59230 (`camel-mail`) is the reference case: the
+ `MimeMultipart` data format with `headersInline=true` copied the MIME
+ headers of the message being unmarshalled onto the `Exchange` with no
+ filter at all. CAMEL-24419 then showed the second half of the lesson - the
+ data format had been given a plain `DefaultHeaderFilterStrategy`, which
+ knows only `Camel*` / `camel*`, so the `mail.smtp.*` namespace that the
+ *consumer* path deliberately filters was still admitted through the
+ unmarshal path. An entry point that filters a narrower namespace than its
+ sibling entry point is a gap, not a difference in configuration.
+* *Structured content modes*, where fields parsed out of the body become
+ headers. CVE-2026-63621 (`camel-knative`) is the reference case: binary-mode
+ CloudEvent attributes arrived as HTTP headers and went through a
+ `HeaderFilterStrategy`, but in structured mode the event was a JSON document
+ in the body and the sender-chosen extension attributes were mapped onto the
+ message directly. A component that filters one content mode must filter
+ every content mode that reaches the same header map.
+* *Transport metadata that is not a header* - query parameters, path segments,
+ subscription names (CVE-2026-55993 `camel-atmosphere-websocket`).
+
+*A filter that is never consulted is not a filter.* CVE-2026-78329
+(`camel-undertow`) is the reference case: `UndertowEndpoint` defaulted its
+`headerFilterStrategy` field to the base `HttpHeaderFilterStrategy` and pushed
+that instance into the HTTP binding it creates lazily, overwriting the
+component-specific `UndertowHeaderFilterStrategy` that the binding had
+installed in its own constructor. The correct strategy was constructed and
+then immediately replaced, so on endpoint-configured routes it never ran - and
+the earlier hardening it carried (CAMEL-23588) had been inert since it
+shipped. The same shape appears outside header filtering: in CAMEL-24412 a
+case-insensitive comparison guarding a `camel-netty-http` security constraint
+sat behind a case-sensitive `startsWith`, so it could never change the
+outcome. Presence of a defence in the source is not evidence that it executes;
+both the reporter and the triager have to establish that the guard is on the
+live path.
+
The prefixed headers of the API-based components - `CamelFhir.*`,
`CamelBox.*`, `CamelOlingo4.*`, `CamelAs2.*` and the other
`camel-api-component` generated producers, which select the API method and its
@@ -535,6 +710,36 @@ auth handler was at the exact path, exposing subpaths of
`/api`, `/admin`,
and permission checks, so a deployment configuring neither accepts the request
unauthenticated).
+Two sub-rules have each now produced more than one advisory and are stated
+explicitly, because a component can satisfy the letter of its option names
+while breaking either one:
+
+* *An unconfigured check must fail closed, not disappear.* CVE-2026-66908
+ (`camel-platform-http-main`) is the reference case: when neither `jwtIssuer`
+ nor `jwtAudience` was configured the code built the `JWTAuth` instance from
+ the keystore alone, so inbound tokens were checked for signature and expiry
+ only and the `iss` and `aud` claims were not validated at all - silently,
+ with the server starting and reporting authentication as enabled. The same
+ shape underlies CVE-2026-53913 above, and CAMEL-24411, where the
+ `camel-oauth` processors returned normally from the paths on which they do
+ *not* authenticate the caller, so the rest of the route ran and overwrote
+ the challenge the processor had just prepared. A security component that
+ cannot perform a check it advertises must refuse to start or refuse the
+ request; leaving the check out is not a neutral default.
+* *The authorization decision and the action must be computed from the same
+ value.* CVE-2026-40022 (`camel-platform-http-main`) mounted the Vert.x
+ sub-router at `<path>*` while the auth handler sat at the exact path, so
+ sub-paths of `/api`, `/admin` and `/observe/info` were dispatched but not
+ guarded. CAMEL-24412 is the normalization variant: `camel-netty-http`
+ stripped the endpoint context-path with a case-sensitive `startsWith` before
+ evaluating the security constraint, while dispatch matched the path
+ case-insensitively - so a request whose context-path differed only by case
+ reached the route but was evaluated against an unstripped target, matched no
+ inclusion, and an unmatched target counts as unrestricted. Wherever routing
+ and authorization each normalize a path, a host or an identifier, they have
+ to normalize it identically; a divergence between them is an auth bypass
+ even when both sides are individually correct.
+
==== Information disclosure of secrets or sensitive Exchange state
Code paths that write secrets, internal Exchange state, file contents or
@@ -580,6 +785,28 @@ CVE-2026-46591 (`camel-neo4j` Cypher injection via JSON
property names
interpolated into the query), CVE-2014-0003 (`camel-xslt` extension-function
invocation from untrusted stylesheet input).
+==== Argument injection into an external process Camel launches
+
+Some components do their work by invoking an external binary. Where the
+component assembles that command line, untrusted input must reach the child
+process only as data - a value in the argument vector - and must never be able
+to add or alter an argument. A component that concatenates untrusted input
+into a command string, or that accepts caller-supplied extra arguments without
+validating them against a known-safe set, lets an attacker turn a data field
+into an option the binary acts on: an output-path flag, a configuration-file
+flag, or anything else the tool exposes.
+
+Historical example: CVE-2026-40047 (`camel-docling`), where insufficient
+validation of custom CLI arguments passed to the `docling` binary enabled both
+argument injection and path traversal.
+
+This class sits next to the first row of _Security properties and violation
+severity_ ("untrusted data is never turned into executed code or OS
+commands"). It is distinct from the route-author case: a route author who
+writes an `exec` endpoint with an attacker-controlled command is out of scope
+per _Out of scope_; the class here is the framework building the argument
+vector on the route author's behalf.
+
=== Out of scope
The following are *not* framework vulnerabilities. They are intentional design,
@@ -723,17 +950,32 @@ they are, the change is announced through the normal
upgrade-guide channel.
strip or normalise them at the trust boundary, exactly as for a query string
built from untrusted input - while the *specific* set of semantic headers a
component honours is necessarily component-by-component and is documented on
- each component page. The framework itself is in scope only when a *consumer*
- maps untrusted wire input into those headers as part of its own default
- behaviour without an effective inbound `HeaderFilterStrategy` (the same
- inbound-filter class as the Camel-header item under _In-scope vulnerability
- classes_, e.g. CVE-2026-33454 in `camel-mail`); the path-traversal class
- applies independently where such a header navigates outside a configured root
- (e.g. CVE-2018-8041).
+ each component page. The framework itself is in scope whenever an *inbound
+ mapping site* - a consumer, a data format, a structured content mode or a
+ transport binding - maps untrusted input into those headers as part of its
+ own default behaviour without an effective inbound `HeaderFilterStrategy`
+ (the same inbound-filter class as the Camel-header item under _In-scope
+ vulnerability classes_, e.g. CVE-2026-33454 in `camel-mail`); the
+ path-traversal class applies independently where such a header navigates
+ outside a configured root (e.g. CVE-2018-8041).
++
+This limitation is about *semantic* headers - the ones a component reads as
+payload data. It does not extend to a component's own *control* headers, which
+select a target, an operation, or the transport and its credentials. Those are
+internal to the component however they are spelled, they belong in its inbound
+filter set even when they carry no `Camel` prefix, and a report about one is
+in scope rather than route-author responsibility. See the control-header
+definition under the Camel-header class in _In-scope vulnerability classes_.
* *Aggregation repositories that persist Java objects assume the backing store
is trusted.* JDBC, Cassandra, Infinispan, LevelDB, Consul and similar
repositories are state stores for routes the operator wrote; the operator is
responsible for keeping write access to that store inside the trust boundary.
+ This assumption is about *state the route itself wrote and reads back*. It
+ does not extend to the names and metadata a remote data store reports for
+ objects other principals put there - blob and object keys, remote file names,
+ listing entries - which are untrusted input under _Adversary model_ and have
+ produced accepted path-traversal advisories (CVE-2026-66906, CVE-2026-60093,
+ CVE-2026-66907).
* *Many components inherit the security posture of their underlying client.*
`camel-jms` inherits JMS-broker client behaviour; `camel-kafka` inherits
Kafka-client behaviour; cloud SDK components inherit the SDK's TLS and auth
@@ -772,10 +1014,11 @@ Disposition is `KNOWN-NON-FINDING` (see _Triage
dispositions_).
the consumer is vulnerable."* Bean-based dispatch via internal headers
is the public contract for letting a route control component behaviour;
see the second bullet under _Known limitations_. A finding is in scope
- only when a *consumer* promotes an untrusted-origin value into that
- namespace without an effective `HeaderFilterStrategy` - the
- Camel-header / bean-dispatch class under _In-scope vulnerability
- classes_.
+ only when an *inbound mapping site* - a consumer, a data format, a
+ structured content mode or a transport binding - promotes an
+ untrusted-origin value into that namespace without an effective
+ `HeaderFilterStrategy`, the Camel-header / bean-dispatch class under
+ _In-scope vulnerability classes_.
* *"Application-level header X (`To`, `Subject`, HTTP `X-...`, JMS
property, AMQP / MQTT / CoAP / Kafka header) is not stripped, therefore
the consumer is vulnerable."* Application-level headers are part of
@@ -784,6 +1027,16 @@ Disposition is `KNOWN-NON-FINDING` (see _Triage
dispositions_).
namespace. See the third bullet under _Known limitations_ and the
application-headers point under _Security properties not provided_.
The route author sanitises at the trust boundary.
++
+*This entry applies only to headers the component reads as payload
+ data.* Before using it, check what header X actually does: if it
+ selects a target, an operation, or the transport and its credentials,
+ it is a control header, it is in scope however it is spelled, and the
+ disposition is not `KNOWN-NON-FINDING` - see the control-header
+ definition under the Camel-header class in _In-scope vulnerability
+ classes_, and the advisories cited there for `websocket.*`, `gridfs.*`,
+ `irc.*`, `operationName` and `mail.smtp.*`. The absence of a `Camel`
+ prefix decides nothing on its own.
* *"`DefaultHeaderFilterStrategy` can be bypassed by changing the case
(`caMEL`, `CAMEL`)."* The default strategy is case-insensitive out of
the box (`Camel`, `CAMEL` and `caMEL` are filtered identically); see
@@ -821,6 +1074,16 @@ Disposition is `KNOWN-NON-FINDING` (see _Triage
dispositions_).
signature), not a routing or identification primitive. See the
constant-time-comparison point under _Security properties not
provided_.
+* *"The component declares a `HeaderFilterStrategy`, therefore its
+ inbound headers are filtered."* This is the inverse error, and it is a
+ reason not to close a report rather than a non-finding: a strategy that
+ is constructed and then overwritten, or one that is consulted on one
+ entry point but not on a sibling entry point, filters nothing on the
+ path that matters (CVE-2026-78329, CAMEL-24419). Establishing that the
+ declared strategy is the instance actually consulted on the live path
+ is part of triaging any report in this class - see "a filter that is
+ never consulted is not a filter" under the Camel-header class in
+ _In-scope vulnerability classes_.
* *"A deprecated component still ships and has a CVE."* Deprecated
components are in limited scope; the primary remediation is the
documented migration to the supported replacement, not necessarily a
@@ -865,7 +1128,12 @@ not provided_), not to close the report ad hoc.
| No claimed property is violated, but a recurring misuse or scanner
pattern makes the framework elect to harden the default or add a
defence-in-depth check at maintainer discretion. Reported privately;
- typically shipped without a CVE; documented in the upgrade guide.
+ usually shipped without a CVE; documented in the upgrade guide. The PMC
+ may still publish an advisory when a sibling component's accepted
+ finding would otherwise make the change look like a silent fix -
+ CVE-2026-56140 (`camel-aws2-sns`) documents an inbound filter added to
+ a producer-only component with no reachable injection path, alongside
+ CVE-2026-46456 in `camel-aws2-sqs` where the path was reachable.
| _Known limitations_, _Guidance for component authors and reviewers_
| `OUT-OF-MODEL: trusted-input`
@@ -913,6 +1181,27 @@ not provided_), not to close the report ad hoc.
| _Reporting a vulnerability_ (PMC review), upgrade-guide entry
|===
+*An incomplete fix is a new finding, not a re-opening.* Where a published
+advisory's remediation turns out to leave a reachable path, the residue is
+triaged from scratch against this model and, if it lands on `VALID`, gets its
+own advisory rather than an amendment to the original. This has happened often
+enough to be a standing rule rather than a case-by-case call, and it takes
+three recognisable shapes:
+
+* *The fix was applied to some call sites but not all* - CAMEL-24413 and
+ CAMEL-24420, where the `camel-hazelcast` deserialization filter added for
+ CVE-2026-43865 was not applied to the remaining Camel-built configurations.
+* *The mitigation is present but under-strength* - CVE-2026-42527, where the
+ default `ObjectInputFilter` pattern itself admitted `java.net.**`.
+* *The mitigation can be side-stepped by a different route to the same sink* -
+ CVE-2026-43866, where a forged `DefaultExchangeHolder` bypassed the filter
+ added for CVE-2026-40860; and CVE-2026-46591, the incomplete-fix follow-on to
+ CVE-2025-66169 in `camel-neo4j`.
+
+A corollary for reporters and for triage tooling: "this was already fixed in
+CVE-X" is not a disposition. The claim to check is whether the specific path in
+the new report is closed, not whether the component was patched once.
+
== Configuration variants that change the model
The posture described above is not a single fixed setting; a small number of
@@ -1089,6 +1378,14 @@ YAML::
uri: direct:trusted-pipeline
----
====
+* *On older releases, also strip the control-header namespaces of the
+ components in the route.* The framework filters the `Camel*` namespace by
+ default and has fixed the non-prefixed control headers it shipped
+ (`websocket.*`, `gridfs.*`, `irc.*`, `operationName`, `mail.smtp.*`) as
+ those were found; each fix names its affected and fixed versions in the
+ corresponding advisory at link:/security/[]. Where a deployment cannot yet
+ move to a release that carries them, add the relevant prefixes to the
+ `removeHeaders` pattern at the trust boundary alongside `Camel*`.
* *Do not enable Java serialisation on consumers exposed to untrusted
networks.* In particular, do not set `allowJavaSerializedObject=true`,
`transferException=true`, or `mapJmsMessage=true` on a JMS consumer when the
@@ -1126,12 +1423,54 @@ with the security model.
`DefaultHeaderFilterStrategy` (or re-implement the case-insensitive `Camel*`
match); and add any of the component's *own* internal headers that fall
outside the `Camel*` namespace to the filter set explicitly.
++
+Three follow-up checks decide whether that is actually true of the change in
+front of you:
++
+--
+. *Which of the component's headers are control headers?* Any header that
+ selects a target, an operation, or the transport and its credentials is
+ internal regardless of its spelling and must be in the inbound filter set.
+ Prefer the `Camel` prefix for new header constants so the default filter
+ covers them; where a legacy non-prefixed name has to stay, filter its
+ namespace explicitly. Never place a control header outside the filter and
+ rely on the route author to strip it.
+. *Is the strategy the one actually consulted?* Constructing the right
+ strategy is not enough - check that no endpoint default, binding
+ constructor or setter replaces it before use, and that it is reached on
+ every path, not just the one the test exercises (CVE-2026-78329).
+. *Does every entry point filter the same namespace?* A consumer, a data
+ format's `unmarshal`, each structured content mode, and any query-parameter
+ or transport-metadata mapping all populate the same header map. When one is
+ hardened, harden the others in the same change (CVE-2026-59230 and
+ CAMEL-24419, CVE-2026-63621).
+--
* *Does the component deserialise into a Java object?* If it uses
`ObjectInputStream.readObject()`, an XStream-style unmarshaller or a
polymorphic Jackson reader on input the operator did not explicitly control,
the default must be safe: either an `ObjectInputFilter` is installed, the
feature is opt-in only, or the component refuses to deserialise unknown
- types.
+ types. Look for the indirect route as well as the direct one: a third-party
+ API that advertises "JDK serialization" reaches
+ `ObjectInputStream.readObject()` on your behalf, and grepping only for
+ `new ObjectInputStream(` will miss it. Where the component can route the
+ stream through `CamelObjectInputStream`, it inherits the default JEP-290
+ filter added in 4.22 (CAMEL-24296); that is a floor, not a substitute for
+ a filter scoped to the types the component actually expects.
+* *Does the component build a local path, a URL or a command line out of a
+ name it did not choose?* Remote object and blob names, listing entries and
+ file names reported by a backing service are untrusted (see _Adversary
+ model_). Normalize the result and verify it resolves inside the configured
+ directory before use; in Camel expressions prefer `${file:onlyname}` over
+ `${file:name}`, which returns the remote name verbatim. When passing values
+ to an external binary, put them in the argument vector as data and validate
+ any caller-supplied extra arguments against a known-safe set.
+* *Does the component map the output of an AI model into the `Exchange`?*
+ Model output - including tool-call field names and arguments - is untrusted
+ input, not a trusted control channel. Filter it into the header map through
+ the same strategy any other inbound mapping site would use, and bind
+ tool arguments to the parameters the tool actually declares
+ (CVE-2026-49042).
* *Does a `@UriParam` control a security-relevant default?* Mark it with the
appropriate `security = "insecure:*"` attribute so the policy enforcement
framework can warn or fail on it. The four categories are `secret`,
@@ -1145,7 +1484,14 @@ with the security model.
* *Does the component provide authentication or authorization?* It must
enforce what its option names claim - validate token issuers, audiences and
signatures; cover every sub-path the matching handler advertises; fail
- closed.
+ closed. Two specific traps, each behind more than one advisory: a check
+ whose configuration is absent must fail closed or refuse to start, never
+ silently drop out of the validation chain (CVE-2026-66908, CVE-2026-53913,
+ CAMEL-24411); and where the component normalizes a path, host or identifier,
+ the authorization decision must be computed from exactly the same normalized
+ value as the dispatch decision (CVE-2026-40022, CAMEL-24412). A denial path
+ must also stop the exchange, not merely set a response that a later step
+ can overwrite.
* *Does the change relax a default?* New defaults err toward "denied unless
opted in" for the four `security` categories. If a default must be relaxed,
the change requires a corresponding upgrade-guide entry and PMC review.