This is an automated email from the ASF dual-hosted git repository.
davsclaus 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 e6e5621639a1 CAMEL-24655: camel-coap - guard case-insensitive header
filtering
e6e5621639a1 is described below
commit e6e5621639a1e39540feb57d5f1b3687069ce565
Author: Andrea Cosentino <[email protected]>
AuthorDate: Tue Sep 8 20:11:24 2026 +0200
CAMEL-24655: camel-coap - guard case-insensitive header filtering
The CoAP consumer maps the URI query parameters of an incoming request
into Exchange headers, running each through the endpoint
HeaderFilterStrategy first. The default strategy filters names starting
with Camel/camel case-insensitively, so a remote peer cannot set Camel
internal headers that steer downstream processing. That behaviour was
correct but untested, so a refactoring of the consumer could silently
drop it - the exact regression the CVE-2025-27636 family was about.
Adds CoAPHeaderInjectionTest: sends requests carrying a Camel internal
header name as a URI query parameter in four casings and asserts it is
never mapped onto the Exchange, while an ordinary query parameter still
is. Verified to fail when the filter call in CamelCoapResource is
removed. Test-only; no production code is modified.
Closes #26208
Co-authored-by: Claude Opus 5 <[email protected]>
---
.../apache/camel/coap/CoAPHeaderInjectionTest.java | 83 ++++++++++++++++++++++
1 file changed, 83 insertions(+)
diff --git
a/components/camel-coap/src/test/java/org/apache/camel/coap/CoAPHeaderInjectionTest.java
b/components/camel-coap/src/test/java/org/apache/camel/coap/CoAPHeaderInjectionTest.java
new file mode 100644
index 000000000000..82a14c81ad15
--- /dev/null
+++
b/components/camel-coap/src/test/java/org/apache/camel/coap/CoAPHeaderInjectionTest.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.coap;
+
+import java.util.List;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.eclipse.californium.core.CoapClient;
+import org.eclipse.californium.core.coap.MediaTypeRegistry;
+import org.eclipse.californium.core.coap.Request;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+/**
+ * The CoAP consumer maps URI query parameters of an incoming request into
Exchange headers. A remote peer must not be
+ * able to use that to set Camel internal headers, whatever casing it uses, as
those steer downstream processing (bean
+ * method dispatch, file names, and so on).
+ */
+public class CoAPHeaderInjectionTest extends CoAPTestSupport {
+
+ private static final String[] CAMEL_HEADER_VARIANTS = {
+ "CamelBeanMethodName", "camelBeanMethodName",
"caMELBeanMethodName", "CAMELBEANMETHODNAME" };
+
+ @Test
+ void camelHeadersInUriQueryAreFilteredRegardlessOfCase() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.expectedMessageCount(CAMEL_HEADER_VARIANTS.length);
+
+ CoapClient client = createClient("/TestResource");
+ for (String variant : CAMEL_HEADER_VARIANTS) {
+ Request request = Request.newPost();
+ request.setURI(client.getURI() + "?" + variant +
"=malicious&normalParam=value");
+ request.setPayload("test");
+
request.getOptions().setContentFormat(MediaTypeRegistry.TEXT_PLAIN);
+ assertNotNull(client.advanced(request), "no CoAP response received
for variant " + variant);
+ }
+
+ MockEndpoint.assertIsSatisfied(context);
+
+ List<Exchange> received = mock.getReceivedExchanges();
+ for (int i = 0; i < CAMEL_HEADER_VARIANTS.length; i++) {
+ String variant = CAMEL_HEADER_VARIANTS[i];
+ Message in = received.get(i).getIn();
+ // the Camel header map is case-insensitive, so this lookup also
catches the other spellings
+ assertNull(in.getHeader(variant),
+ "a Camel internal header must not be injectable through a
CoAP URI query parameter: " + variant);
+ assertEquals("value", in.getHeader("normalParam", String.class),
+ "a non-Camel query parameter must still be mapped to a
header");
+ }
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ fromF("coap://localhost:%d/TestResource", PORT.getPort())
+ .to("mock:result")
+ .setBody(constant("ok"));
+ }
+ };
+ }
+}