Skip to content

REPRO-2026-00330: Verified Reproduction

REPRO-2026-00330: MariaDB 13.0.1-rc RCE chain: F-09 GRANT PROXY priv-esc MDEV-40470 + /proc/self/maps ASLR leak + F-05 SYS REFCURSOR heap UAF → JOP to system as uid 999 mysql , pure SQL from a low-priv account

REPRO-2026-00330 is verified against mariadb/server · github. Affected versions: F-09 affects every released MariaDB version (confirmed 13.0.1 through 10.6.27). F-05 unfixed at HEAD as of 2026-08-03. Vulnerability class: RCE. This critical reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00330.

REPRO-2026-00330 mariadb/server · github RCE Aug 23, 2026 .txt
Severity
CRITICAL
Confidence
HIGH
Reproduced in
61m 33s
Tool calls
217
Spend
$6.73
01 · Overview

What Is REPRO-2026-00330?

REPRO-2026-00330 is a critical-severity RCE vulnerability affecting mariadb/server F-09 affects every released MariaDB version (confirmed 13.0.1 through 10.6.27). F-05 unfixed at HEAD as of 2026-08-03.. Pruva has independently reproduced it and publishes a verified, runnable proof-of-concept (reproduction REPRO-2026-00330).

02 · Severity & CVSS

REPRO-2026-00330 Severity

REPRO-2026-00330 is rated critical severity.

CRITICAL threat level
Weakness CWE-266

Critical — the most severe class — typically remotely exploitable with severe impact. Treat as an emergency.

03 · Affected Versions

Affected mariadb/server Versions

mariadb/server · github versions F-09 affects every released MariaDB version (confirmed 13.0.1 through 10.6.27). F-05 unfixed at HEAD as of 2026-08-03. are affected.

How to Reproduce REPRO-2026-00330

$ pruva-verify REPRO-2026-00330
or curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00330/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-00330

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

pure SQL statements from a USAGE-only account over TCP/3306: GRANT PROXY ... IDENTIFIED VIA '', LOAD DATA INFILE '/proc/self/maps', 128MiB user variable with baked JOP layout, CALL uaf5()

Attack chain
  1. mariadb client
  2. TCP/3306
  3. GRANT PROXY priv-esc (MDEV-40470)
  4. maps ASLR leak
  5. F-05 SYS_REFCURSOR UAF (sp_cursor_array::get_cursor_by_ref)
  6. Materialized_cursor::open() virtual dispatch
  7. JOP D2
  8. D1
  9. system()
How the agent worked 478 events · 217 tool calls · 1h 1m
1h 1mDuration
217Tool calls
93Reasoning steps
478Events
13Dead-ends
Agent activity over 1h 1m
Policy
1
Support
9
Repro
206
Judge
32
Variant
225
Verify
1
0:0061:21

Root Cause and Exploit Chain for REPRO-2026-00330

Versions: reproduced on 13.0.1-MariaDB-ubu2604 (pinned image).

A USAGE-only MariaDB account with TCP reachability to port 3306 achieves remote code execution as uid=999(mysql) on the stock, unmodified MariaDB 13.0.1-rc Docker image (mariadb@sha256:ef34af04bda12e6c85395328af78d562176c34fb29ae52063a4eb0d68fa7b3e9) using nothing but SQL statements. The chain combines: (F-09) a GRANT PROXY ... IDENTIFIED VIA '' privilege escalation that hijacks the root account with an empty password (MDEV-40470); a server-side LOAD DATA INFILE '/proc/self/maps' read that discloses the live PIE and libc base addresses (ASLR defeat); a 128 MiB user-variable buffer whose address is discovered by diffing /proc/self/maps from SQL; and (F-05) a SYS_REFCURSOR use-after-free in sp_cursor_array::get_cursor_by_ref() whose freed 1792-byte array chunk is reclaimed by an exact-fit heap spray, redirecting a virtual dispatch into a two-gadget JOP chain (D2 → D1) that calls libc system() with an attacker-chosen command string.

  • Package/component: mariadb/server — server core (sql/sql_acl.cc GRANT PROXY handling; sql/sp_cursor.{cc,h} cursor array).
  • Affected versions: reproduced on 13.0.1-MariaDB-ubu2604 (pinned image). Per the advisory, F-09's fix (commit dbd60d0ad8d) exists only on dev branches and is absent from every released version 13.0.1 → 10.6.27; F-05 is unfixed upstream (no commits to sql/sp_cursor.{cc,h} since the 13.0.1 tag).
  • Risk level: Critical. Any authenticated low-privilege database user gains full OS command execution as the mysql service account (uid 999), i.e. complete database-server compromise, remotely, over the normal SQL protocol.

Impact Parity

  • Disclosed/claimed maximum impact: code execution as uid 999 (mysql) from a USAGE-only account via pure SQL over TCP/3306.
  • Reproduced impact from this run: identical — attacker-chosen shell commands executed as uid=999(mysql) on the stock pinned image in 6/6 fresh processes (5 scripted + 1 manual calibration run), each with fresh ASLR.
  • Parity: full.

Root Cause

  1. F-09 — GRANT PROXY privilege escalation (MDEV-40470). GRANT PROXY ON CURRENT_USER() TO 'root'@'%' IDENTIFIED VIA ''; passes an empty authentication clause. LEX_USER::has_auth() returns false, so the privilege check in check_alter_user() is skipped, while replace_user_table() still applies the (empty) password — replacing root's credentials with an empty password. One statement, any authenticated user. Fix: commit dbd60d0ad8d (dev branches only; no released version has it). Runtime proof: after the statement, login as root with --skip-password succeeds (CURRENT_USER()=root@%), and the pre-escalation negative control shows ERROR 1045 on LOAD DATA INFILE and ERROR 1227 on SET GLOBAL.

  2. ASLR defeat. With the FILE privilege obtained in step 1 and secure_file_priv unset (stock), LOAD DATA INFILE '/proc/self/maps' loads mariadbd's own memory map into a table; plain SELECTs return the PIE base (first r--p 00000000 mapping of /usr/sbin/mariadbd) and the libc base. Fresh values every process (observed 0x63abb3250000, 0x57b3cea2c000, 0x55b611d36000, 0x76955fffe000-area, 0x731cf3fff000-area).

  3. F-05 — SYS_REFCURSOR use-after-free (unfixed 0day). sp_cursor_array::get_cursor_by_ref() returns an interior pointer into a Dynamic_array. When a cursor's open() executes SQL that opens more cursors (grow5() opens 16 cursors, then OPEN p FOR SELECT spray128()), the array grows, my_realloc frees the old 1792-byte storage (16×112 B), and the caller's cached pointer dangles. A heap spray of 128 session user variables of exactly 1784 bytes (SET @e3sNNN=@e3pad, glibc exact-fit for the 1792-byte chunk) reclaims the freed storage with attacker bytes, placing a controlled pointer V at offset 0x20 (the result member of sp_cursor). Materialized_cursor::open() then dispatches virtually: mov rax,[result]; call [rax+0x20].

  4. JOP to system(). The fake vtable V lives in a 128 MiB user-variable buffer whose address is learned via the maps diff (glibc gives such large allocations a dedicated mmap; the slot is reused across free+realloc, so the self-referential pointer baked by SQL stays valid; buffer data begins at region+0x30 — verified this run via gdb on the live process). Layout: V+0x20=D2, V+0xa0=system, V+0xa8=V+0x140 (cmd ptr), V+0x100=D1, V+0x140="sh -c '<cmd>'". Dispatch: call [rax+0x20] → D2 (call *0x100(%rax), PIE+0x80da77) → D1 (mov rdi,[rax+0xa8]; call [rax+0xa0], PIE+0xe3075b) → system() (libc+0x5c560). All three gadget offsets were re-verified with objdump against the binaries extracted from the pinned image in this run (logs/repro/gadget_check.log).

Reproduction Steps

  1. bundle/repro/reproduction_steps.sh (run twice consecutively — both runs exited 0).

  2. The script: installs mariadb-client/binutils if missing; pulls the pinned image; verifies the D2/D1/system gadget offsets in the extracted binaries; then performs two independent attempts, each against a freshly created container (fresh datadir, root password labpass, USAGE + appdb.*-only lowpriv account, fresh ASLR). Each attempt runs bundle/repro/exploit_mdev40470.py, a pure-SQL driver (mariadb client over TCP/3306) that executes the whole chain and finally reads the marker file id > /tmp/mdev40470_pwned_attemptN the payload wrote inside the container.

  3. Expected evidence: per attempt — F-09 done - root login with EMPTY password, leaked PIE/libc bases, stable 128 MiB slot, session death on CALL uaf5(), and marker content uid=999(mysql) gid=999(mysql) groups=999(mysql); script exits 0 only when both attempts confirm.

    Note on the exploit driver: it is the published PoC (github.com/dinosn/mariadb-13-rce-lab @ 6ac868e1) with one robustness fix in the /proc/self/maps region discovery — on this kernel the fresh 128 MiB mmap is sometimes VMA-merged with an adjacent pre-existing anonymous region (observed merged sizes 0x8022000 and 0x10002000), which the stock exact-size filter missed. The patched logic tracks all anonymous rw-p regions and handles both new-region and grew-region cases. Gadget offsets, sizes, DATA_OFF (0x30) and the whole chain are unchanged.

Evidence

  • bundle/logs/reproduction_steps.log — full scripted run (exit 0, 2/2).
  • bundle/logs/repro/version_check.log13.0.1-MariaDB-ubu2604.
  • bundle/logs/repro/gadget_check.log — objdump verification of D2/D1/system.
  • bundle/logs/repro/vuln_attempt_1.log, vuln_attempt_2.log — per-attempt chain transcripts (distinct ASLR bases).
  • bundle/logs/repro/marker_attempt_1.log, marker_attempt_2.loguid=999(mysql) gid=999(mysql) groups=999(mysql).
  • bundle/logs/repro/vuln_attempt_token.log + marker_attempt_token.log — additional run writing the unique token MDEV40470_CHAIN_EXEC_1785762660.
  • bundle/logs/repro/negative_control_lowpriv.log + bundle/repro/negative_control_1.json — identical procedure without F-09: ERROR 1045 (FILE), ERROR 1227 (SUPER), no marker, no crash; the escalation is the linchpin.
  • bundle/repro/runtime_manifest.json — tcp_peer entrypoint, service/health/ target-path flags, pinned-image target identity.
  • Environment: Docker 27.5.1 daemon, host kernel 6.8, container glibc 2.43; ASLR enabled (/proc/sys/kernel/randomize_va_space default); PIE binary.

Recommendations / Next Steps

  • F-09 (MDEV-40470): backport commit dbd60d0ad8d to all maintained release branches; reject empty IDENTIFIED VIA '' authentication clauses in GRANT PROXY / treat them as authenticated changes requiring check_alter_user() privileges.
  • F-05: fix sp_cursor_array::get_cursor_by_ref() callers to re-validate the cursor reference after open() (or pin the array storage / use index-based lookup) so growth during a nested open cannot dangle the cached pointer.
  • Defense in depth: set secure_file_priv to a dedicated directory in the stock image; consider local_infile=0 and restricting FILE privilege.
  • Until patched releases exist, any authenticated account must be treated as equivalent to full OS code execution as the mysql user.

Additional Notes

  • Idempotency: reproduction_steps.sh was run twice consecutively; both runs passed (4/4 scripted attempts + 1 manual + 1 token run = 6/6 total). Each attempt recreates the container from the pinned image, so no state carries over.
  • No fixed negative control exists: the F-09 fix is not in any released version and F-05 is unfixed upstream, so no released image can serve as a fixed build. The in-band negative control (same procedure without the F-09 escalation) demonstrates the privilege gate; the gadget-offset verification binds the result to the exact pinned binaries.
  • Kernel-dependent VMA merging was the only environmental deviation from the published PoC (its exact-size maps filter). The patched discovery was verified against gdb ground truth (marker bytes ABCD found at region+0x30, confirming DATA_OFF=0x30; chunk header 0x8000ff2 IS_MMAPPED at region+8).
  • The server process crashes after system() returns (mariadbd is PID 1, so the container exits); marker files persist in the container layer and are read after docker start. This post-exploit housekeeping is the only non-SQL step and is not part of the exploitation.

REPRO-2026-00330 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:002:45
0:00
session startedaccounts/fireworks/models/kimi-k3 · MDEV-40470-F05-RCE-CHAIN · REPRO-20
0:10
0:12
web search
0:15
web search
0:58
0:58
extract_facts
no facts extracted
1:00
1:00
supportclaim_contract
1:15
1:15
1:15
1:25
1:25
1:25
1:25
1:33
1:33
1:33
1:45
1:45
$python3 -c " import json d=json.load(open('bundle/learning/exploit_knowledge_preflight.json')) for r in d['results']: rec=r['record'] print(rec['id'], '|', rec.get('state'), '|', rec.get('record_type') or rec['body'].get('record_type'), '|', rec.get('title')) "
0.3s
EXPLOIT-KNOWLEDGE PREFLIGHT REVIEW REQUIRED: `run_shell` is blocked until this agent calls `review_exploit_knowledge_preflight` with snapshot_sha256 `dc98b2e663eaa7e653978c790c2f557b7c2584b2bd260f1bc21100b764b28ca0` and exactly one disposition for each candidate ID [0533adf6-0e1f-44ca-afb8-6cb2faafab11, 1491a4cf-2d16-4a81-98dd-3d114a69bb9c, 1755d479-acfb-4e6b-9199-5abf23eb5fbc, 5dab43ae-009f-4c25-a4fd-7a7b9a874b38, 6de687bb-a6a7-4522-b134-121b577fdb0c, 7c845cfe-5dab-41d2-9f50-d71160b7cf40, 981e5...
1:45
error

Unknown error

1:53
1:53
2:04
2:04
2:29
2:30
2:45
08 · How to Fix

How to Fix REPRO-2026-00330

Coming soon

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

10 · FAQ

FAQ: REPRO-2026-00330

Is REPRO-2026-00330 exploitable?

Yes. Pruva independently reproduced REPRO-2026-00330 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-00330).

How severe is REPRO-2026-00330?

REPRO-2026-00330 is rated critical severity.

What type of vulnerability is REPRO-2026-00330?

REPRO-2026-00330 is classified as CWE-266, a RCE vulnerability.

Which versions of mariadb/server are affected by REPRO-2026-00330?

mariadb/server F-09 affects every released MariaDB version (confirmed 13.0.1 through 10.6.27). F-05 unfixed at HEAD as of 2026-08-03. is affected by REPRO-2026-00330.

How can I reproduce REPRO-2026-00330?

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-00330 reproduction verified?

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

References for REPRO-2026-00330

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