# RCA Report — CVE-2026-40022

## Summary

Apache Camel's embedded HTTP server (`camel-platform-http-main`) enables an
authentication bypass on subpaths whenever a **non-root context path** (e.g.
`/api` or `/admin`) is configured via `camel.server.path` /
`camel.management.path` and the operator does **not** explicitly set
`camel.server.authenticationPath` / `camel.management.authenticationPath`.
The `BasicAuthenticationConfigurer` and `JWTAuthenticationConfigurer` derive
the authentication-protected path from `properties.getPath()` (the context path)
and only special-case the exact root `/`. Because the Vert.x sub-router that
hosts the platform-http routes is mounted with `router.route(path + "*").subRouter(subRouter)`,
sub-router route matching is performed relative to the consumed context prefix,
so an auth handler registered at the literal context path (e.g. `/api`) never
matches the relative subpaths that the business routes are served on. The net
effect is that unauthenticated requests to any subpath (e.g. `/api/hello` or
`/admin/observe/info`) reach protected routes and management endpoints without
being challenged for credentials.

## Impact

- **Package / component affected:** `org.apache.camel:camel-platform-http-main`
  (and the Vert.x engine `camel-platform-http-vertx` it drives). The same
  `*AuthenticationConfigurer` classes protect both the embedded HTTP server
  (`HttpServerConfigurationProperties`) and the embedded management server
  (`HttpManagementServerConfigurationProperties`).
- **Affected versions:** `camel-platform-http-main` 4.14.1 before 4.14.6,
  and 4.18.0 before 4.18.2 (fixed in 4.14.6, 4.18.2, and 4.20.0).
- **Risk level:** High (advisory severity moderate). Unauthenticated remote
  access to protected business routes and management endpoints. The management
  `/observe/info` endpoint can disclose runtime metadata (user, working/home
  directory, process id, JVM and OS info).

## Impact Parity

- **Disclosed / claimed maximum impact:** Authentication bypass
  (`authz_bypass`) — unauthenticated HTTP access to protected routes and
  management endpoints on the embedded server.
- **Reproduced impact from this run:** `authz_bypass` on the `api_remote`
  surface — an unauthenticated `GET /api/hello` to a real running Camel Main
  embedded HTTP server returns `200 OK` (body `ok`) on the vulnerable build,
  while the identical configuration on the fixed build returns
  `401 Unauthorized`. Authentication is demonstrably *enabled* (credentials
  succeed, and the fixed build rejects without them).
- **Parity:** `full` for the claimed authentication-bypass surface. The
  management-server variant (`/admin/observe/info`) shares the identical
  `*AuthenticationConfigurer` code path and root cause; this run focuses on the
  server-route surface, which is the primary claimed remote vector.
- **Not demonstrated:** No code execution, memory corruption, or crash is
  claimed or produced — the issue is purely an authorization bypass, which is
  what was reproduced.

## Root Cause

In the vulnerable releases the authentication path is resolved inline inside
each configurer, e.g. in `BasicAuthenticationConfigurer.configureAuthentication(...)`:

```java
String path = isNotEmpty(properties.getAuthenticationPath())
        ? properties.getAuthenticationPath()
        : properties.getPath();          // <-- falls back to the CONTEXT path
// root means to authenticate everything
if ("/".equals(path)) {
    path = "/*";
}
```

When `camel.server.authenticationPath` is unset, `path` becomes the configured
context path (e.g. `/api`). Only the exact root `"/"` is widened to `"/*"`;
any other context path is left as an **exact** path. That path is then stored
on the `AuthenticationConfigEntry` and registered on the Vert.x sub-router in
`VertxPlatformHttpServer`:

```java
// auth handler registered on the sub-router at the (exact) context path
authenticationConfig.getEntries()
    .forEach(entry -> subRouter.route(entry.getPath()).handler(entry.createAuthenticationHandler(vertx)));
...
// sub-router mounted for the context prefix
router.route(configuration.getPath() + "*").subRouter(subRouter);   // e.g. router.route("/api*").subRouter(subRouter)
```

The platform-http consumer route (`platform-http:/hello`) is registered on the
*same* sub-router as `subRouter.route("/hello")`. Because `Route.subRouter()`
delegates routing to the sub-router **relative to the consumed `/api` prefix**,
a request to `/api/hello` is matched inside the sub-router against the relative
path `/hello`. The auth handler registered at the literal `/api` therefore
never matches a relative subpath, so the `/hello` route is reached without the
authentication handler ever executing. A request without credentials returns
`200 OK` (the route body) instead of `401 Unauthorized`.

### Fix

The fix (tags `camel-4.14.6`, `camel-4.18.2`, `camel-4.20.0`) centralizes path
resolution in a new default method on `MainAuthenticationConfigurer` and makes
both configurers call it:

```java
/**
 * Resolves the effective authentication path. When no explicit authentication
 * path is configured, defaults to {@code /*} so that all subpaths under the
 * context path are protected.
 */
default String resolveAuthenticationPath(String authenticationPath, String contextPath) {
    if (ObjectHelper.isNotEmpty(authenticationPath)) {
        return authenticationPath;
    }
    return "/*";
}
```

With the default now `"/*"`, the auth handler is registered at
`subRouter.route("/*")`, which matches the relative subpath `/hello` (and every
other subpath) → an unauthenticated request is challenged with `401`.

- Advisory: https://camel.apache.org/security/CVE-2026-40022.html
- Fix location: `components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/authentication/`
  (`MainAuthenticationConfigurer`, `BasicAuthenticationConfigurer`,
  `JWTAuthenticationConfigurer`) in tags `camel-4.14.6` / `camel-4.18.2` /
  `camel-4.20.0`.

## Reproduction Steps

1. The self-contained script is `bundle/repro/reproduction_steps.sh`.
2. It materializes a minimal Camel `Main` application that:
   - registers a route `from("platform-http:/hello").setBody(constant("ok"))`,
   - enables the embedded HTTP server with `camel.server.enabled=true`,
     `camel.server.path=/api`, `camel.server.port=8080`,
   - enables basic authentication with `camel.server.authenticationEnabled=true`
     and `camel.server.basicPropertiesFile=auth.properties`
     (`user.admin=secret`), **without** setting `camel.server.authenticationPath`
     (the vulnerable precondition).
   It builds and runs the **real** embedded Camel HTTP server twice with
   **identical** application code and configuration, changing only the Camel
   version: `4.14.5` (vulnerable) and `4.14.6` (fixed). For each it sends real
   HTTP requests to `http://localhost:8080/api/hello` with and without
   credentials and records the responses. It confirms the bypass when the
   vulnerable build returns `200` without credentials while the fixed build
   returns `401` without credentials, then writes
   `bundle/repro/runtime_manifest.json`.
3. Expected evidence:
   - `bundle/logs/vulnerable_4.14.5_no_creds.txt` → `HTTP/1.1 200 OK` body `ok`
   - `bundle/logs/fixed_4.14.6_no_creds.txt` → `HTTP/1.1 401 Unauthorized` with
     `WWW-Authenticate: Basic realm="vertx-web"`
   - `bundle/logs/vulnerable_4.14.5_app.log` and `fixed_4.14.6_app.log` showing
     `camel.server.authenticationEnabled = true`, `camel.server.path = /api`,
     `camel.server.basicPropertiesFile = auth.properties`, and
     `Vert.x HttpServer started on 0.0.0.0:8080` for the respective version.
   - `bundle/repro/runtime_manifest.json` with `service_started`,
     `healthcheck_passed`, and `target_path_reached` all `true`.

## Evidence

- `bundle/logs/reproduction_summary.log` — contrast table and verdict.
- `bundle/logs/vulnerable_4.14.5_no_creds.txt`:
  ```
  HTTP/1.1 200 OK
  transfer-encoding: chunked

  ok
  ```
- `bundle/logs/fixed_4.14.6_no_creds.txt`:
  ```
  HTTP/1.1 401 Unauthorized
  WWW-Authenticate: Basic realm="vertx-web"
  content-length: 12

  Unauthorized
  ```
- `bundle/logs/vulnerable_4.14.5_app.log` (key lines):
  ```
  ... camel.server.authenticationEnabled = true
  ... camel.server.basicPropertiesFile = auth.properties
  ... camel.server.path = /api
  ... Apache Camel 4.14.5 (camel-1) is starting
  ... Vert.x HttpServer started on 0.0.0.0:8080
  ... Apache Camel 4.14.5 (camel-1) started in 149ms
  ```
- `bundle/logs/fixed_4.14.6_app.log` (key lines):
  ```
  ... camel.server.authenticationEnabled = true
  ... camel.server.basicPropertiesFile = auth.properties
  ... camel.server.path = /api
  ... Apache Camel 4.14.6 (camel-1) is starting
  ... Vert.x HttpServer started on 0.0.0.0:8080
  ... Apache Camel 4.14.6 (camel-1) started in 154ms
  ```
- Both `with_creds` probes return `200 OK`, proving credentials are accepted and
  the route itself is healthy.
- Environment: OpenJDK 17.0.19, Apache Maven 3.9.12, Apache Camel
  `camel-platform-http-main` 4.14.5 / 4.14.6 (Vert.x 4.5.24 engine),
  Linux x86_64.

## Recommendations / Next Steps

- **Upgrade** `camel-platform-http-main` to 4.14.6 (4.14.x LTS), 4.18.2
  (4.18.x LTS), or 4.20.0 as appropriate.
- **Defense in depth:** explicitly set `camel.server.authenticationPath=/*`
  (and `camel.management.authenticationPath=/*`) even on patched versions so
  protection does not depend on the default-resolution behavior.
- **Audit:** review any deployed Camel Main apps using a non-root
  `camel.server.path` / `camel.management.path` with authentication enabled but
  no explicit `authenticationPath`; those are the exposed instances.
- **Regression test:** add an integration test in Camel that asserts an
  unauthenticated request to a subpath under a non-root context path returns
  `401` when authentication is enabled (this run's contrast is a direct
  template: vulnerable `200` vs fixed `401`).

## Additional Notes

- **Idempotency:** `reproduction_steps.sh` was run twice consecutively; both
  runs exited `0` and reproduced the identical contrast (`vulnerable 200` /
  `fixed 401`). The script frees port 8080 and rebuilds cleanly each run.
- **Real product, not a mock:** the proof runs the actual `org.apache.camel.main.Main`
  embedded HTTP server (Vert.x/Netty) and drives it with real `curl` HTTP
  requests over localhost — a genuine `api_remote` boundary.
- **Property note:** the ticket's reproduction text references
  `camel.server.authenticationMechanism=basic` and
  `camel.server.authenticationUsers[0].username/password`. Those properties do
  not exist in the vulnerable 4.14.x / 4.18.x releases; the real basic-auth
  mechanism in those versions is selected by setting
  `camel.server.basicPropertiesFile` (a Vert.x `PropertyFileAuthentication`
  file), which is what this reproduction uses. The authentication-bypass root
  cause is identical regardless of how credentials are configured.
- **Exact-context-path behavior:** on the vulnerable build a request to the
  exact context path `/api` (no creds) returns `404`, not `401`, because the
  auth handler registered at the literal `/api` never matches a relative
  (prefix-stripped) sub-router path — so in practice *no* path is protected,
  making the bypass total. The fixed build returns `401` for both `/api` and
  `/api/hello` because the handler is registered at `/*`.
