flowable / flowable/flowable-engine
[SECURITY] Java deserialization of `type=serializable` REST variables (CVSS 8.0), unsandboxed deployable artifacts, order-column SQLi, HTTP-task SSRF
- Lingua principale
- Java
- Stelle
- 9.5k
- Fork
- 2.9k
- Merge medio
- 7h 8m
- PR unite (30g)
- 2
Descrizione
> Consolidated to avoid flooding the tracker — happy to split on request. All findings verified dynamically by the reporter on the standard flowable-rest deployment (2026-09-02/03).
## Finding 1 — Unrestricted deserialization of `type=serializable` variables (High)
**Summary.** The REST API accepts multipart variables of `type=serializable`; the raw bytes pass through `ObjectInputStream.readObject()` on the engine host with **no class allow-list**. We confirmed `readObject` executes and reconstructs attacker-supplied objects. The shipped `-Djdk.serialFilter=maxarray=...;maxdepth=...` bounds graph **size only** — gadget classes on the engine classpath remain viable.
**Affected:** flowable-engine @ `1663e588179d` (flowable-app-rest module), standard flowable-rest deployment.
**CVSS v3.1 (self-assessed):** 8.0 — `AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H` (AC:H for gadget dependency; demo deployments with published credentials raise this materially).
**Attack Path**
```
Step 1: POST /runtime/tasks (create a task; any assignee)
Step 2: POST /runtime/tasks/{taskId}/variables (multipart)
name=serV1 type=serializable scope=local
file=@
→ stored, then read through ObjectInputStream on read-back
Step 3: GET /runtime/tasks/{taskId}/variables/serV1
→ server has executed readObject() and reconstructs the object
```
(Same sink on `/runtime/executions/{id}/variables` and `/runtime/process-instances/{id}/variables`.)
**Prerequisites:** REST API credentials. The official sample deployments ship well-known demo credentials (`rest-admin`), which makes this effectively unauthenticated RCE surface there.
**Proof of Concept (executed).** Uploading a serialized `java.util.Date` (epoch `1700000000000`) returned:
```json
HTTP 201 {"name":"serV1","scope":"local","type":"date","value":"2023-11-14T22:13:20Z"}
```
The server executed `readObject()` and **recognized the attacker-supplied object as a Date**, echoing its value — arbitrary bytes are deserialized server-side; a GET returns the same reconstructed value.
**Impact.** With any gadget present in the engine's large dependency surface: full RCE. Without: unexpected object construction side effects and resource exhaustion.
**Suggested fix.** Reject `type=serializable` on REST input (keep JSON-friendly types; opaque `binary` otherwise) and add a strict class allow-list `jdk.serialFilter` for any path that must deserialize.
## Finding 2 — Deployable process artifacts execute without a sandbox (High as deployed)
**Summary.** These are designed extension points; the risk is that no expression/script sandbox or allow-list exists and the REST demo profile makes deployment a single authenticated request. All of the following were **executed** on the engine host:
| Artifact | Result (observed) |
|---|---|
| `serviceTask flowable:type="shell"` (`command=echo`) | OS command executed; stdout returned as process variable (`out=SH_RCE_OK`) |
| `` (JSR-223) | script evaluated (`execution.setVariable("sv","SCRIPT_1337")`) |
| `serviceTask flowable:class="java.lang.Thread"` | class loaded + instantiated (type-check error proves `Class.forName`) |
| `flowable:expression="${1337+10}"` (BPMN), DMN `outputEntry` `${1337+10}`, CMMN + Event Registry delegate expressions | JUEL evaluated (`1347` returned in `returnVariables`) |
**Suggested fix.** Provide an opt-in sandbox profile for deployments where engine admins are not OS-trusted: disabled shell tasks by config, restricted `ScriptEngine` lookup, blocked type resolution in expressions.
## Finding 3 — `orderAscendingColumn` / `orderDescendingColumn` SQL injection (Medium)
`GET /management/tables/{table}/data?orderAscendingColumn=ID_'` → HTTP 500 with a raw H2 driver syntax error; ordering by `KEY_` vs `NAME_` yields different result orders — a workable error/boolean-based injection over the authenticated management API.
**Suggested fix:** validate the column identifier against the table's actual columns; never interpolate the raw parameter.
## Finding 4 — HTTP service task `requestUrl` expression SSRF (Medium)
A deployed HTTP service task whose `requestUrl` resolves from a process variable makes the engine issue a GET to an arbitrary URL at process start. Verified: a loopback listener captured the engine's `GET /V27_SSRF`. Combined with Finding 2's deployment path this is an internal-network probing primitive.
**Suggested fix:** URL validation / egress policy for HTTP tasks.
---
*All steps executed by the reporter against a live deployment. AI tools were used to help discover and prepare these findings. Reported 2026-09-07; suggesting a 90-day coordinated disclosure window — happy to coordinate on GHSA/CVE.*
Guida per i contributori
Nessuna guida per i contributori indicizzata per questo repository
Direzione di ricerca
Inizia tracciando il flusso di flowable-rest per le multipart serializable variables, i deployment artifacts, l’ordinamento delle management tables e la gestione di requestUrl delle HTTP service tasks, usando i REST endpoints elencati e i comportamenti osservati come punti di riproduzione. Il lavoro è completato quando i maintainer concordano su correzioni circoscritte per tutti e quattro i findings e ogni comportamento dispone di una verifica di regressione; coordina separatamente la divulgazione.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- java, sql
- Ambito
- api, backend, databases, security
- Tipo di issue
- Bug
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Stato di attività
- Attiva
- Chiarezza
- Abbastanza chiara
- Idoneità per principianti
- 25/100