CAMEL-24084: Apply header filter strategy to structured-mode CloudEvent extension headers#24724
Conversation
…nt extension headers The Knative consumer filters inbound HTTP headers through KnativeHttpHeaderFilterStrategy, but structured content mode (application/cloudevents+json) mapped the remaining event fields (extensions) onto the message headers without a HeaderFilterStrategy, inconsistent with the binary/HTTP-header path. Route structured-mode extension fields through a HeaderFilterStrategy so Camel* headers (matched case-insensitively) are filtered consistently on both content modes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
🌟 Thank you for your contribution to the Apache Camel project! 🌟 🐫 Apache Camel Committers, please review the following items:
|
gnodet
left a comment
There was a problem hiding this comment.
Good security fix — closes the gap where structured-mode CloudEvent extension fields bypassed the HeaderFilterStrategy that the binary/HTTP-header path already applied.
What works well:
- Correctly uses
DefaultHeaderFilterStrategy.applyFilterToExternalHeaders(IN direction) which filtersCamel*/camel*case-insensitively viainFilterStartsWithwithlowerCase=true. - All three CE spec versions (v1_0, v1_0_1, v1_0_2) are updated consistently.
DefaultHeaderFilterStrategyis the right choice here —KnativeHttpHeaderFilterStrategyonly adds OUT-direction HTTP headers, so for the IN path they behave identically, and using the base class avoids a cross-module dependency (camel-knative-component→camel-knative-http).- The
mapExtensionAsHeaderhelper centralises the lowercasing + filtering logic nicely.
Test quality:
- Both positive (regular extension
myextensionpasses through) and negative (camelfilename→CamelFileNameis filtered) assertions are present. - Parameterised with
@EnumSource(CloudEvents.class)to cover all spec versions.
Checklist:
- Tests included and parameterised
- Upgrade guide entry added (4.22)
- Security — consistent filtering on both content modes
- No public API changes (
mapExtensionAsHeaderisprotectedon a package-private class) - No other paths with the same gap (binary mode filters at the transport layer; batch mode throws
UnsupportedOperationException)
Reviewed with Claude Code on behalf of gnodet. This review was generated by an AI agent and may contain inaccuracies; please verify all suggestions before applying.
|
🧪 CI tested the following changed modules:
🔬 Scalpel shadow comparison — Scalpel: 11 tested, 28 compile-only — current: 10 all testedMaveniverse Scalpel detected 39 affected modules (current approach: 10).
|
davsclaus
left a comment
There was a problem hiding this comment.
Clean, well-scoped security fix that closes a header-injection gap in structured-mode CloudEvent processing.
What was wrong: In binary content mode, KnativeHttpHeaderFilterStrategy filters Camel* headers from inbound HTTP headers. But in structured content mode (application/cloudevents+json), extension fields from the JSON payload were mapped directly onto message headers without any HeaderFilterStrategy — allowing an attacker to inject framework-internal headers (e.g. camelfilename → accessible as CamelFileName via Camel's case-insensitive header map).
Why the fix is correct: DefaultHeaderFilterStrategy defaults to filtering headers starting with Camel/camel (case-insensitive, with lowerCase=true). The new mapExtensionAsHeader() helper lowercases keys with Locale.US before passing them through the filter, so all casing variants are caught — consistent with the binary-mode path.
Test coverage: The new test sends both a regular extension (myextension — asserted to pass through) and a malicious one (camelfilename — asserted to be filtered via Exchange.FILE_NAME == null), correctly exercising Camel's case-insensitive header lookup.
Upgrade guide: Present and well-written.
Claude Code review on behalf of davsclaus. This review was generated by an AI agent and may contain inaccuracies; please verify all suggestions before applying.
Summary
The Knative consumer filters inbound HTTP headers through
KnativeHttpHeaderFilterStrategy, so Camel-internal headers (Camel*) are not mapped onto the message. When a CloudEvent is received in structured content mode (application/cloudevents+json),CloudEventProcessors.decodeStructuredContentmapped the remaining event fields (extensions) directly onto the message headers without applying anyHeaderFilterStrategy— inconsistent with the binary/HTTP-header path.This routes structured-mode extension fields through a
HeaderFilterStrategybefore setting them as headers, soCamel*headers (matched case-insensitively) are filtered consistently on both content modes. Ordinary CloudEvent extension attributes are unaffected.Changes
AbstractCloudEventProcessor: add aHeaderFilterStrategyand a sharedmapExtensionAsHeader(...)helper.CloudEventProcessors: route the extension mapping (all spec versions) through the helper.KnativeHttpTest: new test asserting a regular extension is propagated and aCamel*-named field is filtered.Notes
main/4.21.x,DefaultHeaderFilterStrategyfiltersCamel*inbound by default; the4.18.x/4.14.xbackports will setsetInFilterStartsWith(CAMEL_FILTER_STARTS_WITH)explicitly.Claude Code on behalf of Andrea Cosentino (@oscerd)
🤖 Generated with Claude Code