# Variant RCA Report — CVE-2026-40022 (camel-platform-http-main)

## Summary

A distinct authentication-bypass **variant** of CVE-2026-40022 reproduces on the
**patched** Apache Camel `camel-platform-http-main` 4.14.6 (and by extension
4.18.2 / 4.20.0). The official fix (commit `a9ebee94af976ac2afd7906d2e76673067d8be86`)
only changes the **default** path resolution: when
`camel.server.authenticationPath` / `camel.management.authenticationPath` is
**not** set, the auth handler is now registered at `/*` on the Vert.x sub-router,
so all subpaths are protected. **Explicit** `authenticationPath` values are
still returned verbatim by the new `MainAuthenticationConfigurer.resolveAuthenticationPath`
(which receives but **ignores** the `contextPath` argument) and are registered
**relative to the sub-router**. The user-facing Javadoc describes
`authenticationPath` as "the HTTP url path ... that is protected", which
encourages an operator to set it to the context prefix (e.g. `/api` or
`/admin`). Because that value is matched relative to the consumed context
prefix, `authenticationPath=/api` protects only `/api/api`, **not** `/api/hello`;
`authenticationPath=/admin` protects only `/admin/admin`, **not**
`/admin/observe/info`. On the patched 4.14.6 build, an unauthenticated
`GET /api/hello` still returns `200 OK`, and an unauthenticated
`GET /admin/observe/info` still returns `200 OK` with a JSON body leaking
runtime metadata (`user`, `user.dir`, `user.home`, `pid`, JVM vendor/version,
OS name/version/arch). This is the same root cause and the same sink as the
parent CVE, reached via a different data path (explicit `authenticationPath`
equal to the context prefix) that the fix does not cover.

## Fix Coverage / Assumptions

- **Invariant the fix relies on:** when `authenticationPath` is unset, default
  the registered auth path to `/*` so every subpath under the context is
  protected.
- **Code paths the fix explicitly covers:** the *unset/default* branch of
  `BasicAuthenticationConfigurer` and `JWTAuthenticationConfigurer` (both the
  `HttpServerConfigurationProperties` and `HttpManagementServerConfigurationProperties`
  overloads). The fix's own test `BasicAuthenticationSelectivePathTest` covers
  exactly one explicit form, `/secure/*`, asserted as deliberate *selective*
  protection (`/api/secure/data` → 401, `/api/public` → 200).
- **What the fix does NOT cover:** any explicit `authenticationPath` that equals
  or starts with the context path (`/api`, `/api/*`, `/admin`, `/admin/*`).
  `resolveAuthenticationPath` returns such values verbatim; they are registered
  relative to the sub-router and therefore do not match the real subpaths. There
  is no normalization, no startup warning, and no doc clarification; the
  `contextPath` parameter to `resolveAuthenticationPath` is dead code.

## Variant / Alternate Trigger

Two entry points, same data-path pattern (explicit `authenticationPath` set to
the context prefix), same sink:

1. **Embedded HTTP server (business routes):**
   - Config: `camel.server.path=/api`, `camel.server.authenticationEnabled=true`,
     `camel.server.basicPropertiesFile=auth.properties`,
     `camel.server.authenticationPath=/api` (explicit, the doc-encouraged form).
   - Attack: unauthenticated `GET http://host:8080/api/hello`.
   - Sink: `VertxPlatformHttpServer.addAuthenticationHandlersStartingFromMoreSpecificPaths`
     → `subRouter.route(entry.getPath())` where `entry.getPath()` = `/api`
     (relative), mounted under `router.route("/api*").subRouter(subRouter)`.
     The relative `/api` matches only absolute `/api/api`; `/api/hello` is
     served without the auth handler.
2. **Embedded management server (info disclosure):**
   - Config: `camel.management.path=/admin`, `camel.management.infoEnabled=true`,
     `camel.management.authenticationEnabled=true`,
     `camel.management.authenticationPath=/admin` (explicit).
   - Attack: unauthenticated `GET http://host:8081/admin/observe/info`.
   - Same sink via the management sub-router; the `/observe/info` route
     (`ManagementHttpServer.setupInfo`, registered at relative `/observe/info`)
     is reached without auth and returns runtime metadata JSON.

Files/functions involved:
- `org.apache.camel.component.platform.http.main.authentication.MainAuthenticationConfigurer.resolveAuthenticationPath(String, String)`
- `BasicAuthenticationConfigurer.configureAuthentication(...)` / `JWTAuthenticationConfigurer.configureAuthentication(...)` (server + management overloads)
- `org.apache.camel.component.platform.http.vertx.VertxPlatformHttpServer` (sub-router mount + `addAuthenticationHandlersStartingFromMoreSpecificPaths`)
- `org.apache.camel.component.platform.http.main.ManagementHttpServer.setupInfo` (info-disclosure endpoint)
- `org.apache.camel.main.HttpServerConfigurationProperties` / `HttpManagementServerConfigurationProperties` (`authenticationPath` Javadoc)

## Impact

- **Package/component affected:** `org.apache.camel:camel-platform-http-main`
  (driving `camel-platform-http-vertx`). The same `*AuthenticationConfigurer`
  classes and the same `VertxPlatformHttpServer` engine protect both the
  embedded HTTP server and the embedded management server.
- **Affected/tested versions:** confirmed on fixed `4.14.6` (also reproduced on
  vulnerable `4.14.5` for contrast). The explicit-path branch is unchanged
  between the two, so 4.18.2 / 4.20.0 are expected to behave identically.
- **Risk level:** High. Unauthenticated remote access to protected business
  routes; unauthenticated remote disclosure of runtime metadata (OS, JVM, pid,
  username, working directory, home directory) via the management `/observe/info`
  endpoint.

## Impact Parity

- **Disclosed/claimed maximum impact (parent CVE):** `authz_bypass` —
  unauthenticated HTTP access to protected routes and management endpoints.
- **Reproduced impact from this variant run:** `authz_bypass` on the
  `api_remote` surface, **on the patched build**. Unauthenticated
  `GET /api/hello` → `200 OK` (body `ok`); unauthenticated
  `GET /admin/observe/info` → `200 OK` with a JSON body disclosing `user`,
  `user.dir`, `user.home`, `pid`, JVM and OS details. Credentials are accepted
  (with-creds → 200), and the default case is correctly fixed (401), proving
  authentication is genuinely enabled and the route is healthy.
- **Parity:** `full` for the claimed authentication-bypass surface, plus a
  concrete information-disclosure demonstration on the management surface.
- **Not demonstrated:** no code execution, memory corruption, or crash is
  claimed or produced — the issue is an authorization bypass (with info
  disclosure), which is what was reproduced.

## Root Cause

`VertxPlatformHttpServer` mounts the platform-http routes on a sub-router:
`router.route(configuration.getPath() + "*").subRouter(subRouter)`. Inside that
sub-router, route matching is performed **relative to the consumed context
prefix**. The authentication handler is registered on the same sub-router at
`entry.getPath()`:
```java
authenticationConfig.getEntries().stream()
    .sorted(this::compareUrlPathsSpecificity)
    .forEach(entry -> subRouter.route(entry.getPath()).handler(entry.createAuthenticationHandler(vertx)));
```
The CVE's root cause was that, when `authenticationPath` was unset, `entry.getPath()`
became the exact context path (e.g. `/api`), which as a *relative* path matches
only `/api/api`. The fix made the *unset* case resolve to `/*` (which, as a
relative path, matches every subpath). **But the same root cause persists for any
explicit `authenticationPath` that includes the context prefix**: the value is
returned verbatim by `resolveAuthenticationPath` and registered relative to the
sub-router, so it never matches the real subpaths. The fix addressed the
default-resolution branch only; it did not normalize, validate, or warn about
explicit values, and the user-facing Javadoc continues to describe
`authenticationPath` in absolute-URL-path terms that invite the vulnerable
configuration.

- Fix commit: `a9ebee94af976ac2afd7906d2e76673067d8be86`
- Advisory: https://camel.apache.org/security/CVE-2026-40022.html

## Reproduction Steps

1. The self-contained script is `bundle/vuln_variant/reproduction_steps.sh`.
2. It materializes a minimal Camel `Main` application (route
   `from("platform-http:/hello").setBody(constant("ok"))`) with
   `camel-platform-http-main` + `camel-management` + `camel-console`, builds it
   against the **vulnerable** `4.14.5` and the **fixed** `4.14.6` using a shared
   Maven cache, and for each version runs four configurations against the real
   embedded Vert.x HTTP server:
   - business server, explicit `camel.server.authenticationPath=/api` (BYPASS)
   - business server, default (no `authenticationPath`) (CONTROL)
   - management server, explicit `camel.management.authenticationPath=/admin` (BYPASS)
   - management server, default (CONTROL)
   For each it sends real `curl` requests with and without credentials to
   `/api/hello` and `/admin/observe/info` and records the responses. It writes
   `bundle/vuln_variant/runtime_manifest.json` and `bundle/logs/variant_summary.log`.
3. Expected evidence (on the fixed 4.14.6):
   - `bundle/logs/fixed_biz_default_no_creds.txt` → `HTTP/1.1 401` (fix works)
   - `bundle/logs/fixed_biz_bypass_no_creds.txt` → `HTTP/1.1 200 OK` body `ok` (BYPASS)
   - `bundle/logs/fixed_mgmt_default_info_no_creds.txt` → `HTTP/1.1 401` (fix works)
   - `bundle/logs/fixed_mgmt_bypass_info_no_creds.txt` → `HTTP/1.1 200 OK` JSON
     with `user`, `dir`, `home`, `pid`, JVM/OS (BYPASS + info disclosure)
   - `bundle/logs/fixed_biz_bypass_app.log` showing
     `camel.server.authenticationPath = /api` and `Vert.x HttpServer started`
     on `Apache Camel 4.14.6`.
   Exit 0 = bypass reproduced on the fixed version.

## Evidence

- `bundle/logs/variant_summary.log` — contrast table + verdict.
- `bundle/logs/fixed_biz_bypass_no_creds.txt`:
  ```
  HTTP/1.1 200 OK
  transfer-encoding: chunked

  ok
  ```
- `bundle/logs/fixed_biz_default_no_creds.txt`:
  ```
  HTTP/1.1 401 Unauthorized
  WWW-Authenticate: Basic realm="vertx-web"
  ```
- `bundle/logs/fixed_mgmt_bypass_info_no_creds.txt`:
  ```
  HTTP/1.1 200 OK
  content-type: application/json
  {"os":{"name":"Linux",...},"java":{"pid":179835,"vendor":"Ubuntu","name":"OpenJDK 64-Bit Server VM","vmVersion":"17.0.19+10-1-26.04.2-Ubuntu","version":"17.0.19","user":"vscode","dir":"/data/.../camel-auth-variant","home":"/home/vscode"},"camel":{"name":"camel-1","version":"4.14.6",...}}
  ```
- `bundle/logs/fixed_mgmt_default_info_no_creds.txt` → `HTTP/1.1 401` (control).
- `bundle/logs/fixed_biz_bypass_app.log` (key lines): `camel.server.authenticationPath = /api`,
  `camel.server.path = /api`, `Apache Camel 4.14.6 (camel-1) is starting`,
  `Vert.x HttpServer started on 0.0.0.0:8080`.
- Vulnerable 4.14.5 contrast: every case returns 200 no-creds (original CVE for
  defaults; same explicit-prefix bypass), confirming the fix changed only the
  default branch.
- Environment: OpenJDK 17.0.19, Apache Maven 3.9.12, Apache Camel
  `camel-platform-http-main` 4.14.5 / 4.14.6 (Vert.x engine), Linux x86_64.

## Recommendations / Next Steps

- **Normalize explicit `authenticationPath` against the context path.** In
  `resolveAuthenticationPath`, if the explicit value equals or starts with
  `contextPath`, strip the prefix and (when the remainder is empty or `/`)
  widen to `/*` so "protect the context" actually protects all subpaths. This
  uses the currently-dead `contextPath` argument.
- **Emit a startup warning** when an explicit `authenticationPath` does not
  start with `/` or does not cover any registered subpath, so a
  doc-encouraged misconfiguration is not silent.
- **Fix the Javadoc** for `setAuthenticationPath` (server + management) to state
  that the path is *relative to the context path*, that a wildcard is required
  to protect subpaths, and that **unset = protect everything under the context**.
- **Add a regression test** for the context-prefix case: `camel.server.path=/api`
  + `camel.server.authenticationPath=/api` must yield `401` for `/api/hello`
  (and the management equivalent for `/admin/observe/info`).
- **Defense in depth for operators:** until a fixed release is available,
  explicitly set `camel.server.authenticationPath=/*` /
  `camel.management.authenticationPath=/*`, and avoid setting these to the
  context prefix.

## Additional Notes

- **Bypass vs alternate trigger:** This is a **bypass** — it reproduces on the
  *patched* 4.14.6 (exit 0), while the parent CVE's default case is correctly
  fixed (401) on the same build with identical app code.
- **Idempotency:** `reproduction_steps.sh` was run twice consecutively; both
  runs exited `0` with the identical contrast (fixed default 401 / fixed
  explicit-prefix 200 / vulnerable all-200). The script frees ports 8080/8081
  and rebuilds cleanly each run.
- **Scope honesty:** Camel's advisory scopes CVE-2026-40022 to the "not
  explicitly set" case, which the fix closes. This variant is therefore best
  framed as an *incomplete fix + documentation footgun*: the same auth-bypass
  sink is reachable on the patched build via a doc-encouraged explicit
  `authenticationPath`. The fix's own `BasicAuthenticationSelectivePathTest`
  blesses selective protection with a relative sub-path (`/secure/*`) as
  by-design; the untested, undocumented context-prefix case (`/api`, `/admin`)
  is the gap.
- **Real product, not a mock:** the proof runs the actual
  `org.apache.camel.main.Main` embedded Vert.x/Netty HTTP server and drives it
  with real `curl` over localhost — a genuine `api_remote` boundary.
