In this finding
The request shape was the bug.
CVE-2026-72898 is a CVSS 10.0 unauthenticated SQL injection in Metabase releases before 0.63.5. It was exploited in the wild and added to CISA's Known Exploited Vulnerabilities catalogue on 11 August 2026.
The vulnerable endpoint is POST /api/session/reset_password. In affected releases, its request schema was an open malli map. Extra body keys passed validation and flowed into the merge inside auth-identity/login!.
That merge did two dangerous things. It let caller-supplied values select the user record. It also created a session whenever a user resolved — even when authentication failed. The response could still be a 400 Invalid reset token while the session had already been written.
Three ways in.
We confirmed three distinct primitives against 0.63.1. They are related, but they are not the same bug.
- 01Subquery injection
A HoneySQL map in
user-idcompiled into theWHERE "id" = …clause as a subquery. That gave unauthenticated SQL execution against the application database. - 02Orphan admin session
Setting
user-data.emailto an existing administrator created an admin session with no SQL injection at all. This was a logic flaw in the session gate, not an injection. - 03Raw stacked SQL
The map form
{"raw": "SQL"}compiled as raw SQL, including stacked statements. We verified it on PostgreSQL and H2. On H2, the default for self-hosted Metabase, it was enough to rewrite the administrator password and log in normally.
What we reproduced.
This is an independent reconstruction. Metabase and CISA disclosed the vulnerability first; our work records our own root-cause analysis, lab reproduction and review of the fix. The research window was 15–17 August 2026, across eight lab rounds on an instance we own.
The full takeover ran end to end against v0.63.1. A crafted reset request returned 400 Invalid reset token, but the injected INSERT had committed. A forged session cookie then returned 200 from /api/user/current with is_superuser=true.
On H2 we also completed the simpler route: a stacked UPDATE changed the administrator password, and a normal login returned a superuser session with access to /api/database.
Two side findings are worth recording. First, the user-data.email path produced a measurable account-existence oracle: a median separation of 112.8 ms with no overlap across 40 randomised samples. Second, we audited whether the session key could leak through the error path. It could not.
What the fix changed.
We decompiled the 0.63.5 security-release jar. The fix has four layers:
- 01Close the request schema
Unknown keys now return
disallowed keyinstead of flowing into the merge. - 02Strip caller-controlled keys
A new
authenticate-owned-keysfilter removesuser-id,user-data,auth-identity, session and provider fields before the merge. - 03Gate the session on success
The merge now requires
success?to be true anduser-idto be a positive integer. That kills both the subquery map and the raw map. - 04Narrow the handler
The reset handler now selects only
tokenandpasswordfrom the request body.
At the time of research, the fix was present in the private security-release jars but not in public master.
What happened in the wild.
Attacks against Metabase Cloud customers ran on 2–3 August 2026. Metabase blocked the affected endpoints on 3 August, patched and notified customers on 6 August, and published the CVE with a KEV listing on 11 August. Metabase's own incident report says fewer than 3% of its cloud customers were compromised. Some self-hosted deployments were affected too.
Publicly reported victims spanned SaaS, developer tooling and fintech. The only public per-instance activity log, from Metabase's report to a Cloud customer, matches the lab chain closely: administrator access at 13:00, 54 queries over the next 12 minutes, an API key created at 13:14, 19 more queries through that key, then the key deleted at 13:17.
Checkly's public postmortem describes a similar shape: an admin session, roughly 26 minutes of read-only warehouse access, no accounts created and no API keys changed. n8n reported variable, non-deterministic rows, which is consistent with a blind oracle. Framework reported names, emails and billing data.
Our reconstruction is consistent with that forensics: stacked raw SQL forges an admin session, the 400 does not stop the write, and the attacker never needs to create an account.
How far the exposure reached.
We enumerated internet-facing Metabase instances passively through Shodan and version-triaged them. The search returned 16,331 results at the time, later 16,349. We collected 15,942 IP:port records.
Of those, 3,065 ran a vulnerable version, and 3,050 exposed the vulnerable endpoint. The hosts resolved to roughly 1,182 company domains and 427 ASN organisations — an estimated 1,500–1,600 companies.
We emailed the operators behind roughly 3,000 affected companies, with the vendor IOC, version evidence and lab-backed reproduction notes. Two organisations responded. Per-target records are intentionally not published.
What this does not prove.
- We did not discover this vulnerability. Metabase and CISA published first. This is an independent reconstruction.
- All exploitation was in our lab. We did not run the chain against any third-party instance. Field work was passive enumeration and notification.
- The exposure count depends on method. Shodan coverage, timeouts and version-detection limits change the number. The endpoint-exposed figure is our triage at that moment, not a permanent census.
- A vulnerable version is not proof of compromise. It shows the route may exist. It does not show that a particular instance was accessed or what data was taken.
- We draw on no client data. Every result comes from lab instances we own and public reporting.