Skip to content

Apache Camel October wave: message-supplied placeholder injection, fail-open guards, gate-vs-router case divergence, and unauthenticated cluster transports

Event in one line: On 2026-10-19 12:32Z Apache published a ~28-GHSA coordinated Camel wave (all fixed 4.18.5 / 4.22.1 / 4.23.0; bands 4.0.0–4.18.4 and 4.19.0–4.22.0, some from 4.4.0/4.7.0/4.11.0/4.15.0). The headline leg turns the already-known CamelHttpUri header override into configuration and secret retrieval: the HTTP producer families ran the attacker-supplied URI string through resolvePropertyPlaceholders() — a facility that reaches OS env vars, JVM system properties, every registered PropertiesFunction including the AWS/Azure/GCP/HashiCorp/IBM/CyberArk/Kubernetes secret functions, and through camel-bean the invocation of a no-argument method on any bean in the registry. A plain static to("http://backend/api") route was sufficient — the route author opted into none of this.

Why this is durable operator content: this is the second full Camel wave in eight weeks (see the August 27 page for the header-mapping/deserialization canon), and it generalizes beyond Camel to every integration/routing framework that (a) resolves placeholders against message content, (b) implements auth as a route processor, (c) hardens one parser path per component, or (d) treats group/multicast membership as authentication. The same-product re-sweep rule fired again: the August wave's header-injection map is exactly where October's critical lives.

Primary sources

GitHub advisories, all published 2026-10-19 12:32Z unless noted:

Advisory CVE Component(s) Boundary
GHSA-394j-cc2x-w9wm CVE-2026-78164 (high) camel-http, camel-vertx-http, camel-undertow, camel-netty-http Message-supplied URI run through resolvePropertyPlaceholders()
GHSA-5m9r-c7qx-c2h6 CVE-2026-80312 (high) camel-oauth Auth processors fall through on failure — fail-open guard
GHSA-pvjg-pwh7-34pj CVE-2026-80343 (high) camel-netty-http Case-sensitive security-constraint match vs differently-cased routing dispatch
GHSA-wqmw-6vq7-3mxp CVE-2026-88900 (high) camel-jgroups Stock JChannel() = no AUTH/encryption; ObjectMessage deserialized on the receive thread with no filter
GHSA-7j2m-8x69-fhvh CVE-2026-78162 (critical) camel-hazelcast Deserialization-filter fix did not reach the doStart() copy-paste twin or the client-mode config builder
GHSA-68m6-7hmq-4c53 CVE-2026-83531 (high, from 4.4.0) dynamic-router-control Predicate and language name taken from message body/headers, then compiled — expression injection
GHSA-wrg6-q24g-59j6 CVE-2026-80344 (high) camel-as2 Async MDN destination taken verbatim from the inbound message — SSRF with attached credentials
GHSA-62ww-q9gh-hmrv CVE-2026-78163 (high, from 4.15.0) camel-docling Body-prefix sniffing picks fetch-URL / local-read / temp-file mode implicitly
GHSA-x4v6-22c3-2wm5 CVE-2026-88901 (high, from 4.7.0) camel-smooks Default Woodstox reader resolves external entities — hardening applied to other XML siblings only
GHSA-x9f8-58m2-93q2 CVE-2026-85250 (high) camel-xpath documentType=InputSource hands payload to JDK-default DocumentBuilder, skipping the hardened default path — XXE
GHSA-qrg3-hxwc-36jm CVE-2026-91858 (medium) camel-fop FEATURE_SECURE_PROCESSING alone does not restrict external access on third-party JAXP factories (Saxon on classpath) — XXE
GHSA-8p5r-xpxr-x2x7 CVE-2026-78165 (high 8.8, bands 2.11.0–4.18.4 / 4.19.0–4.22.0) camel-spring-redis Default JdkSerializationRedisSerializer with no ObjectInputFilter; consumer deserializes every channel message before the Exchange exists
GHSA-c92r-fmfr-3q4w CVE-2026-68571 (high, published 10-16) Apache Kylin 4.0–5.0.4 Special parameter in JDBC URL → code injection (fix 5.0.5)

Tracked thin legs in the same wave (same bands, class-covered or detail-free): camel-core Jgroups-adjacent deserialization, OAuth CSRF (CVE-2026-84178), Shiro/Keycloak auth gaps (CVE-2026-84181/85301), Netty-HTTP/Platform-HTTP case-sensitivity and granularity pair, Crypto-PGP integrity-check validation (CVE-2026-85243), Thrift/AS2 wrong-session data elements (CVE-2026-85245/85296), Knative cert validation (CVE-2026-85247), Tika/Mail/Core input validation (CVE-2026-85249/85314/85312), error-message/secret disclosure legs (Mina/CXF/gRPC/MLLP/HTTP cache), Jetty/Platform-HTTP permissive CORS (CVE-2026-85313/84176), PQC default permissions (CVE-2026-85300), race condition (CVE-2026-85248).

The axes this generalizes

1. Placeholder resolution over message content = secret retrieval and bean invocation

CamelHttpUri / CamelRestHttpUri headers let an inbound message override the producer endpoint URI (known since the August wave's header-injection canon). The October finding: before using that string, HttpHelper.createURL/createMethod, VertxHttpHelper.resolveHttpURI, UndertowHelper.createURL/createMethod, and NettyHttpHelper.createURL — seven call sites — passed it through resolvePropertyPlaceholders(). That facility expands {{...}} against OS env, JVM system properties, and every PropertiesFunction on the classpath: aws-secret, google-secret, azure-keyvault, hashicorp-vault, ibm-cloud-secrets-manager, cyberark, kubernetes-secret — plus camel-bean bean:name,method dispatch onto any registered bean's no-argument method.

  • Audit rule: placeholder/template resolution is safe over deployment configuration, never over exchange content. Grep for resolvePropertyPlaceholders, PropertyPlaceholderConfigurer, {{ handling applied to any value derived from getIn().getHeader() / body. Then enumerate which PropertiesFunctions the deployment registered (they are classpath-visible) — the reachable secret backends are the blast radius.
  • Probe shape (authorized lab): on a route with an HTTP producer and unfiltered inbound headers, send CamelHttpUri: http://{{skillz-canary}}/ against an owned DNS domain: an expansion-triggered lookup to the canary proves resolution ran over attacker content without fetching anything. For bean-invocation proof use an inert no-arg bean that writes a marker file in your own lab registry — never a real bean.
  • Header-override is the entry, resolution is the escalation: even if the URI never reaches the network (malformed after expansion), the expansion side effects (env reads, secret fetches, bean calls) already ran. Proof does not require a successful outbound request.

2. Fail-open route guards: auth processors that don't stop the exchange

camel-oauth's route guards, on failure to establish an authenticated session, returned control to the route instead of terminating the exchange — the request continued to the protected endpoint as if authenticated, on the ordinary request path, no special configuration (CVE-2026-80312).

  • Test rule: on security processors (route-intercepted auth, not container filters), the oracle is the failure path: force an auth failure (invalid/expired token, unreachable IdP if you can induce it) and observe whether the downstream endpoint still executes. A guard that swallows its own failure is indistinguishable from absent on that branch.
  • Fingerprint: 401/403 from middleware vs silent pass-through with normal downstream response. Compare behavior across: no credential, malformed credential, valid-but-revoked credential — a guard that only rejects clean missing credentials is fail-open for everything else.

3. Gate-vs-router normalization divergence (case-sensitivity edition)

camel-netty-http compared the request path against the configured security-constraint context path case-sensitively, while dispatch used a different casing rule — flipping one character's case made the constraint miss while the request still reached the protected endpoint (CVE-2026-80343). No credential needed.

  • This is the same family as Malcolm's Lua-RBAC-vs-nginx decode split (Oct 8) and kin-openapi's decoded-vs-encoded split (Sept 15, folded Oct 15) — the invariant: the security gate and the dispatcher are two parsers; differential-test their path normalization. The battery now covers: case flip (both directions), %xx encoded-vs-decoded, trailing slash/dot, duplicate slashes, ;params, backslash (Windows). Camel adds case as the drift axis for Java servlet-style constraint matching.
  • On any Camel netty-http/undertow deployment with security constraints: replay each protected path with one case-flipped character per segment and compare auth behavior vs dispatch result.

4. Implicit cluster membership = authentication (JGroups, Hazelcast)

camel-jgroups with default config calls new JChannel() — the stock UDP multicast stack with no AUTH protocol and no encryption. Any host that can reach the multicast group or bind the port joins the cluster and sends messages. Every received ObjectMessage was Java-deserialized on JGroups' own receive thread with no ObjectInputFilter (neither camel-jgroups nor the shipped JGroups versions installed one) → any gadget class on the app classpath deserializes before any Camel route logic runs (CVE-2026-88900). camel-hazelcast's critical leg is the incomplete-fix genealogy: the CVE-2026-43865 filter fix never reached ReplicatedHazelcastAggregationRepository.doStart() (a copy-pasted bootstrap block that skipped super.doStart()) or the hazelcastMode=client config builder — so node mode was filtered, client mode was not, for identical configuration (CVE-2026-78162).

  • Recon rule: for middleware that forms implicit clusters (JGroups, Hazelcast, Infinispan, JChannel-based caches, multicast discovery), the cluster join is the auth boundary and by default it is open to the L2 domain. Check for AUTH/SASL/encryption protocol stacks in the shipped config before crediting the app's authentication.
  • Mode-differential audit: client-mode vs node-mode vs aggregation-twin config builders are separate code paths. After any deserialization fix, test every instantiation path — the extends + overridden lifecycle method that skips super.doStart() is a grep-able shape.
  • Validation boundary: lab multicast/unicast lab network, your own classpath canary class, never join a live production cluster or deserialization-probe shared infrastructure.

5. Expression injection via control-plane headers (dynamic-router-control)

The dynamic-router-control endpoint (4.4.0+) took both the routing predicate and the expression language name from the message body or the CamelDynamicRouterPredicate / CamelDynamicRouterExpressionLanguage headers, resolved the language from the CamelContext, and compiled — an attacker-controlled language + expression evaluated inside the process (CVE-2026-83531). With languages like groovy/OGRL/mvel on the classpath this is code execution; even simple/spel reaches data.

  • Rule: control-plane "manage the router" endpoints are attack surface with the same trust level as an admin API, but they speak message headers. Enumerate management/control endpoints whose policy arrives in message content; probe header families named after policy primitives (*Predicate, *Expression, *Language, *Script, *Query).
  • This leg also re-validates the August canon: inbound Camel-* header mapping is the shared enabler — sweep it once, feed every downstream header consumer from the same map.

6. Attacker-picks-the-destination protocol features (AS2 async MDN)

AS2 lets the sender request the MDN receipt be delivered asynchronously to a sender-supplied address; camel-as2 used the inbound-supplied address verbatim — SSRF from the AS2 receiver's position, into internal-only networks, with the deployment's MDN delivery credentials attached (CVE-2026-80344).

  • Generalizes to every protocol with a callback/receipt/webhook-to-supplied-address field (MDN, SMTP DSN, SIP contact, SAML backchannel, payment-return URLs): the destination field is untrusted input, and the outbound leg often carries an identity you never meant to spend there.
  • Hunt: for each inbound "please reply to…" field, check whether the outbound fetch/POST is destination-allowlisted and whether credentials are destination-scoped (the same anti-pattern as the KEDA hashiCorpVault.address leg on the June 22 control-plane page).

7. Implicit mode selection from content prefixes (docling)

DoclingProducer decided what a String body meant by its prefix: http(s):// → remote fetch, leading / or backslash → local file read, else temp-file convert. No endpoint option pinned the mode (CVE-2026-78163) — a route intended to convert text silently became a URL fetcher and local-file reader for anyone who controls the body.

  • Rule: content-sniffed interpretation = attacker-selected code path. Any startsWith-style mode dispatch over untrusted input is a privilege switch: grep for prefix sniffing that routes between fetch / read / execute / convert. Same genealogy as the Oct 9 Nginx UI extractor-before-decide leg.
  • Sibling note: camel-docling also carried the August wave's CLI-argument-injection advisory — same component, second independent boundary in seven weeks. Component-level re-sweep pays.

8. Parser-hardening divergence within and across components

Three XXE legs, three divergence mechanisms:

  • camel-smooks: applied none of the hardening the other Camel XML components have; default Woodstox reader resolves external general/parameter entities and external DTDs (CVE-2026-88901).
  • camel-xpath: hardening lived on the component's default document type; documentType=InputSource fell through to a JDK-default DocumentBuilder — the two types disagree on parser config (CVE-2026-85250).
  • camel-fop: relied on FEATURE_SECURE_PROCESSING alone; on the JDK transformer that is (accidentally) sufficient, but with a third-party JAXP factory (Saxon, present because the app also uses camel-saxon/camel-xslt-saxon) FSP does not restrict external access — the defense's effectiveness depends on which class TransformerFactory.newInstance() happens to return at runtime (CVE-2026-91858).

  • Audit rule: enumerate the runtime factory class, not the intended one — TransformerFactory.newInstance() / DocumentBuilderFactory.newInstance() are SPI-dispatched over the whole classpath; the FSP shape joins JAXB's FEATURE_SECURE_PROCESSING inversion (Oct 12) as a canon: FSP is per-provider limiting, not blocking.

  • Option-differential probe: for every component with parser/config mode switches (documentType, features, providers), run the hardened-path battery against each option value. The vulnerability lives in the option that takes a different code path (also the fingerprint of "sibling-option incomplete fix").

Adjacent wave item worth the note: Apache Kylin JDBC-URL code injection

Apache Kylin 4.0–5.0.4 (fix 5.0.5) published a ten-GHSA wave (12:32Z, some detail-free) whose strongest leg is special parameter in the configured JDBC URL → code injection (CVE-2026-68571). This is now the fourth independent validation of JDBC-connection-URL/parameter class-loading as a standing scan class (Redshift wmmv May 14, openGauss-connector 4fmq Oct 19, Avatica tracked). Kylin's JDBC source config is a management-plane write target — the sibling missing-authz on jdbc source config update (CVE-2026-108766) and the SQLi (CVE-2026-108776) mean an attacker who reaches the analytics console's config API gets URL-injection material directly. Kylin's own framing ("public exposure not common") does not apply to analytics platforms reachable from internal engagement scopes. Rest of the Kylin wave tracked: unauthenticated in-house broadcast + polymorphic deserialization (CVE-2026-108771), SSRF, path confinement on backup deletion, default startup profile without security settings (CVE-2026-108833 — shipped-default-insecure-profile class), info exposure during job manipulation. Second Kylin wave (first tracked Sept 18) — the same-product re-sweep rule fires again for this product.

Late enrichment fold (13:1xZ sweep): camel-spring-redis pre-route deserialization + Johnzon class-name reflection

  • camel-spring-redis default serializer deserializes before any route logic runs (GHSA-8p5r-xpxr-x2x7 / CVE-2026-78165, CVSS 8.8, bands 2.11.0–4.18.4 and 4.19.0–4.22.0, fix 4.18.5/4.22.1): RedisConfiguration.getSerializer lazily built a bare JdkSerializationRedisSerializer whenever no serializer option was configured, and Spring's implementation runs DefaultDeserializer with no java.io.ObjectInputFilter installed. RedisConsumer.setBody applied it to the raw bytes of every message on the subscribed channels before the Exchange was constructed — so no route filter, choice, or validator could observe the payload before readObject executed. Operator axes: (1) pre-route deserialization — on consumer/subscribe-type components, ask what transformation happens before the first route processor; anything that materializes objects from wire bytes at adapter level is exploitable by anyone with Redis publish access (open/unauthenticated Redis instances make the channel itself the attack surface, same trust shape as the jgroups multicast leg on this page). (2) Default-object grep: getSerializer-style lazy-default builders that hand back a JDK-native implementation when the option is unset are the fingerprint; the safe-default direction (fail with an explicit config error) is the fix shape. (3) Recon: on any Java integration stack, enumerate components that consume from shared brokers (Redis pub/sub, JMS, MQTT, Kafka) and check which serializer/codec the default config selects.
  • Apache Johnzon ClassConverter loads and static-initializes an attacker-named class from untrusted JSON (GHSA-66gj-8qvf-qvfh / CVE-2026-71253, 1.0.0–<2.2.0, backport fix 1.3.1): a JSON field value naming a class reaches Class.forName-equivalent loading with static initialization — third independent validation (after openGauss-connector 4fmq and Kylin c92r, both on this page's lineage) of the class-name-from-untrusted-input scan class. Standing grep set unchanged: any converter/mapper/binder that resolves a type name string (@class, @type, typeName, logger/driver/provider properties) must do allowlist-check before the load, because static initializers run on the load itself — a "we only instantiate approved subclasses" check placed after instantiation is already too late.

October 20 late enrichment fold: camel-ftp/sftp remote-listing injection — the server's own directory listing steers read/delete/rename outside the polled directory (3 GHSAs: vqcr/79983, 3m83/79984, cpwx/79985, bands 4.18.0–4.18.4 / 4.19.0–4.22.0, fix 4.18.5/4.22.1)

Updated-feed enrichment landed the full technical detail on the three remote-file path-traversal legs that the 12:32Z wave carried as sparse entries. The shape is new to this page and highly reusable: the remote server's directory listing entries (not a client-supplied path) are concatenated onto the configured directory with no lexical normalization and no containment check (FtpUtils.absoluteFilePath, GenericFileConsumer), and the resulting path becomes the operand for retrieval, deletion (delete=true), and rename/move (move, preMove, moveFailed, readLock=rename) — all executed with the endpoint's own credentials. A listing entry that isn't a single path segment (e.g. ../../secret) resolves outside the polled directory.

Operator axes:

  • Server-controlled-input reversal. Most path-traversal hunting assumes user input in a URL/body; here the trusted side (the FTP/SFTP/SFTP server the integration polls) supplies the tainted value. Audit posture: any consumer that iterates a remote listing and re-uses names verbatim is traversable by a compromised or attacker-controlled remote endpoint — pairing this with the placeholder-injection critical above, a Camel route's remote host is fully attacker-influenced material in two independent ways.
  • Sink battery on listing entries: the same unnormalized name reaches read (data disclosure), delete (destructive), and rename (state manipulation/lock bypass) — when you find the class, prove which subset fires per component; deletion outside the polled dir is the strongest bounded proof on a lab server you own both sides of.
  • Scan posture for integrations: in authorized engagements against integration platforms, the configured remote endpoints are often attacker-writable elsewhere (public FTP forms, partner-managed SFTP); treat "polls an externally-influenced server" as a first-class finding chain, and test containment with a lab server emitting crafted listing entries (../../marker) — proof is a file outside the polled dir being fetched/deleted by the connector's own credentials.
  • Same fix bands as the rest of the wave (4.18.5 / 4.22.1); three GHSAs = per-operation split (retrieve vs delete vs rename), report as one root cause with a per-verb sink table.

October 26 follow-up wave: auth-verdict cache not bounded by token exp, consumer-set S3-key header evaluated as an expression, and the Docling fix's absolute-path blind spot (4 GHSAs, 09:31Z, bands 4.16/4.15/4.8.0–4.18.4 / 4.19.0–4.22.1, fix 4.18.5 / 4.22.2)

The same-product re-sweep fired a third time on this component family — the October 26 09:31Z wave published full-detail legs that extend this page's axes rather than repeating them.

  • camel-keycloak introspection cache admits expired tokens (GHSA-44m5-wqhm-rq65 / CVE-2026-95663, 4.16.0–4.18.4 / 4.19.0–4.22.1, fix 4.18.5/4.22.2): with useTokenIntrospection=true, KeycloakSecurityProcessor accepted whatever the introspection response said (active=true) and never compared exp with the current time on any path; both shipped caches (ConcurrentMapTokenCache, CaffeineTokenCache) expire an entry a fixed wall-clock interval after insertion (default TTL 60 s) without bounding that lifetime by the exp claim the cached response itself carried. A verdict fetched shortly before expiry was replayed to later requests for up to the TTL after the token died, with full roles/permissions. Operator axes: (1) verdict-cache lifetime must be min(cache_ttl, exp − now) — grep any introspection/validation/token-info cache for a TTL set only at insertion time; (2) when the cache fronts the IdP, the RP's only expiry enforcement is whatever the cached verdict carries — "we introspect every request" is false confidence if the introspect result is cached without re-checking exp; (3) timing-shaped probe (authorized lab): mint a short-lived token, replay it in the first cache-TTL window after exp — a 200 with original roles in that window is the whole PoC, no IdP tampering needed. Revocation-window hunting generalizes: any component caching an auth verdict re-creates the revocation-free session side channel even when the IdP is doing everything right.
  • camel-aws2-s3: consumed object names become evaluated expressions in the producer (GHSA-2p39-5856-3v5v / CVE-2026-95664, 4.8.0–4.18.4 / 4.19.0–4.22.1): AWS2S3Utils.determineKey() passed the key value to the Simple language whenever it contained ${ or $simple{ — applied to the CamelAwsS3Key header as well as the configured keyName option, and the header takes precedence over keyName, so configuring the option does not disable the behavior. The killer chain: the aws2-s3 consumer sets CamelAwsS3Key to the name of each object it reads, so in a plain consume→produce route the object name in the source bucket is attacker input (whoever can name/upload an object) that gets expression-evaluated by the producer — route author opted into nothing. Axes: (1) cross-component taint via auto-set headers — a consumer's "metadata" is the next hop's configuration interpreter; enumerate which headers consumers auto-populate and which producers template-expand them (this is section 1's placeholder rule one layer deeper: expression markers, not {{}}, are the trigger here); (2) data-plane values must never enter an expression engine on a marker sniff — "contains ${" is not validation; (3) hunt shape: on any Camel deployment with an S3-consuming route whose bucket accepts uploads from a wider trust zone, plant an object literally named ${...} and watch for evaluation side effects in the downstream leg. Fourth independent Camel validation of expression-evaluation-over-message-content; the component keeps finding new entry points to the same engine.
  • camel-docling incomplete-fix pair (GHSA-76q5-xqfh-7vw2 / CVE-2026-95628 and GHSA-9mgq-6r88-pghr / CVE-2026-95629, 4.15.0–4.18.4 / 4.19.0–4.22.1): the CVE-2026-40047 fix added (a) a --output/-o denylist on CamelDoclingCustomArguments telling callers to use the CamelDoclingOutputFilePath header instead, and (b) validatePathSafety on path-like custom-arg values. Both fixes have a hole: (a) validatePathSafety only rejected relative traversal (a ../ substring or a .. element surviving normalization) — a plain absolute path contains neither and passed unchanged, e.g. as the allowlisted --artifacts-path value pointing docling at any directory the process can read; (b) the denied flag's function moved to the header, which is handed verbatim to --output with no normalization, no containment option, and the converted-document content derived from the (attacker-influenced) input — arbitrary-directory file write with conversion content, left in place after cleanup. Axes: (1) relative-traversal-only checks miss absolute paths — a path-validation diff that never asks "is this absolute?" is the grep-able incomplete-fix shape; (2) denylist-with-recommended-alternative = check where the redirect lands — the fix moved capability to a parameter that received none of the validation the denied parameter had; after any allow/deny fix, enumerate the suggested alternative and run the original battery against it. This component now carries three independent boundaries in eight weeks (Aug CLI-injection, Oct 19 content-prefix mode selection, Oct 26 write-path) — component-level re-sweep keeps paying.
  • Adjacent fail-open sibling: MISP mispguard status-code equivalence miss (GHSA-85gw-r975-r63j / CVE-2026-116372): the security-filtering proxy in front of MISP feed ingestion inspected response bodies only when the HTTP status was exactly 200, passing everything else through unfiltered on the assumption non-200 carries nothing ingestible — but MISP ingests content from other 2xx (201/203/206), so a malicious feed host answers 203 + arbitrary events and bypasses every filter rule. Same failure shape as camel-oauth's fail-open guard (section 2): the guard's else-branch. Generalized rule for any inspecting proxy/sanitizer/WAF shim: enumerate the consumer's full accept-class (which statuses, media types, encodings it will still act on) and diff against what the filter actually inspects; strict-equality dispatch (status != 200 → skip) on a field with an equivalence class is the fingerprint. Bug-hunter angle: for feed/webhook/ingestion integrations fronted by a filter, the 203/206/2xx-with-body battery is a five-minute first probe.

October 26 15:3xZ fold: body-type-conditional XXE protection in camel-saxon + JVM-static OAuth token cache keyed below its own request identity (CVE-2026-90885 / GHSA-xv62-j8hg-7h33 7.5; CVE-2026-94386 / GHSA-m6q9-jx43-w2vp, fix 4.23.0 / 4.22.2 / 4.18.5)

Two more legs on the same product, both generalizing cleanly:

  • camel-saxon XXE fires only for body types that skip Camel's hardened converters. XQueryBuilder's default Saxon Configuration set only a whitespace-stripping option, leaving the parser at JDK defaults (DOCTYPE accepted, external entities resolved). String/byte[] bodies were safe by accident — Camel's XML type converters configure a hardened parser on the way to Source. A body that was already a Source (after convertBodyTo(Source.class) or an upstream component that sets a stream-based Source) went to Saxon unchanged and was parsed with the unprotected Configuration. Axes: (1) security controls implemented in converters are bypassed by input that arrives already in the post-converter type — when a framework sanitizes on the transition into a type, test entry as that type directly; this is the validation-target-vs-write-target family one layer down (parse-path parity by input type). (2) Route-recon shape: on a Camel deployment with an xquery endpoint, the probe battery must include delivering the payload as a stream-based Source via a preceding convert step, not just raw string POSTs. (3) Standing XXE rule restated from the Aug 6 CXF page: inventory parse sites by which component constructs the parser — here the app-level and Camel-converter-level parsers were hardened, the framework-constructed Saxon one was not.
  • camel-oauth OAuthClientCredentialsTokenResolver cached tokens in a JVM-static map keyed on (token endpoint, client ID) only — while the token request also carries the client secret and the requested scope. Two OAuth profiles sharing an IdP client but configured with different scopes or different secrets collide: whichever resolved first populates the entry, and the other is served that foreign token (broader scope, different audience/service, authenticated with a secret it never used) for the token's lifetime. Caching is on by default; pointing several profiles at one IdP client is ordinary usage. Axes: (1) cache keys must cover the full request identity — grep any credential cache for key fields ⊂ request fields; this is the same key-covers-identity rule as the Oct 21 FalkorDB error-vocabulary and OpenFGA cache-collision lineages. (2) Trust-direction note: profiles are deployment-trusted, so the party who gains a wrong-scope token is the receiving service — for red teams that means a hostile/compromised downstream can hold authority its own profile was never granted, and token-scope drift is observable from the resource side. (3) Audit posture on AI-adjacent stacks (camel-openai, langchain4j-agent, huggingface, spring-ai-chat, watsonx all use named OAuth profiles): multi-profile deployments silently share tokens; verify which scopes actually ride outbound from each component with an owned token-recording listener.
  • Same-window sibling tracked without publication: hackney (Erlang HTTP client) five-pack — proxy_auth_fun return value written into the Proxy-Authorization CONNECT-retry line unsanitized (CRLF request splitting, 5qp8/112880: callback return values are attacker-influenced data planes in HTTP client libraries, but class-covered by header-CRLF lineage), plus cert-validation/credential/DoS legs (g7gg/115693, m347/113440, 8c7g/115700, wpmp/97200). Dolibarr admin allowlist-bypass cmdi (3p5c/116219: mysqldump &cmd& chaining around allowlisted basename — argument-position allowlist checked on first token only, known class) and low-priv time-based-blind SQLi (m4jj/116218) tracked. FortiSandbox alternate-path auth bypass (g63q/107656) has no technical detail — tracked-not-promoted per zero-detail precedent; watch for primitive writeups or KEV.

Validation boundaries

  • Authorized lab Camel/Kylin instances only; build the route yourself so the header-mapping and placeholder paths are observable.
  • Prove placeholder expansion with owned-domain canary lookups and inert registry beans writing marker files; never enumerate real secret backends or invoke application beans.
  • Prove XXE legs with owned HTTP callbacks and synthetic local files you placed; no /etc/passwd reads, no internal-service fetches.
  • Cluster transports: own multicast group or loopback unicast config only; never join or probe a production JGroups/Hazelcast cluster.
  • Report per-component with the version band (<4.18.5 / 4.19–4.22.0 / fix 4.23.0) — the ranges are component-specific and several legs are opt-in by component presence.