ZeroDay.cloud
Back to Blog
MariaDB

CVE-2026-32710: MariaDB JSON_SCHEMA_VALID heap buffer overflow leading to RCE

Team Xint CodeMay 410 min read

At ZeroDay.Cloud 2025, Xint Code discovered a heap buffer overflow in MariaDB's JSON schema validation logic that leads to remote code execution.

CVE-2026-32710 vulnerability summary banner


MariaDB is one of the most widely deployed open-source relational databases, powering production workloads across cloud providers, managed services, and on-prem infrastructure alike. Any authenticated user — including low-privilege application accounts — can reach the vulnerable code path with a single SQL statement. No special grants, extensions, or plugins are required.

CVE-2026-32710 is a heap buffer overflow in MariaDB's JSON_SCHEMA_VALID() function that allows an authenticated user to escalate privileges and execute arbitrary operating system commands on the database host. The bug lives in json_get_normalized_string() inside sql/json_schema_helper.cc, which copies a JSON string value into a fixed 128-byte heap buffer without a bounds check.

The vulnerability was discovered by Xint Code, a fully autonomous AI-powered security analysis tool built by Theori, and a working RCE exploit was demonstrated at ZeroDay.Cloud 2025 (London, December 10-11, 2025). The MariaDB team shipped patches on February 4, 2026 across both supported release series (11.4.10, 11.8.6).

We'd like to thank the MariaDB security team for their prompt acknowledgment and resolution of this issue.

If you run MariaDB in production, take action now. Any user who can open a SQL session — whether through stolen credentials, SQL injection, or lateral movement — can reach this code path with a single function call.


Who is affected

The vulnerable function, JSON_SCHEMA_VALID(), is a built-in SQL function available to every authenticated user. The exploitable code path is reached with a single statement:

SELECT JSON_SCHEMA_VALID('{"enum":[0]}', '"AAAA…"');

The affected release series and versions are:

Release seriesAffected versionsFixed version
MariaDB 11.411.4.1 – 11.4.911.4.10
MariaDB 11.811.8.1 – 11.8.511.8.6

Risk assessment

Critical risk: internet-exposed MariaDB with any authenticated access. Because JSON_SCHEMA_VALID() requires no special privileges, any valid session — even one created through a low-privilege application account — is sufficient to trigger the overflow. Managed or multi-tenant environments where the database acts as a trust boundary face elevated risk: a tenant with valid credentials can exploit this bug to compromise the host.

High risk: internal instances reachable via lateral movement. MariaDB credentials are commonly present in application config files, CI/CD pipelines, and secrets managers. A compromised application server often yields database access. SQL injection provides another path: a single injectable parameter gives the attacker the authenticated SQL execution they need.


Remediation

Patch now

The fix was committed upstream on January 9, 2026 and shipped in MariaDB 11.4.10 and 11.8.6 on February 4, 2026.

Upgrade to the patched minor release for your series. MariaDB minor upgrades within a GA series are designed to be compatible; staying on an older minor carries more risk than upgrading.

Cloud managed MariaDB services may roll out patched versions on their own schedules. Check your provider's bulletin.

If you can't patch yet

Reduce exploitability and blast radius while you schedule patching:


How Wiz can help

Wiz customers can identify affected MariaDB instances across their cloud environments:


From SQL to shell

An attacker needs only authenticated SQL access on the target instance. From there, the exploit proceeds in three phases: privilege escalation, address leak, and code execution.

  1. Privilege escalation: The attacker uses the heap overflow to corrupt internal session metadata, granting their connection full superuser privileges. These elevated privileges are then persisted with GRANT ALL.
  2. Address leak: With superuser, the attacker reads /proc/self/maps via LOAD DATA INFILE to determine the MariaDB binary's base address in memory, defeating ASLR.
  3. Code execution: The attacker triggers the overflow a second time to overwrite the global plugin_dir pointer, redirecting it to /tmp. A malicious shared library is loaded as a User-Defined Function, providing arbitrary OS command execution.

Attack flow and impact diagram


Technical deep dive

CVE-2026-32710 is a heap buffer overflow in json_get_normalized_string() (sql/json_schema_helper.cc).

The vulnerable code

When normalizing a JSON string during schema validation, the function allocates a DYNAMIC_STRING with a default capacity of 128 bytes via init_dynamic_string(), then copies je->value_len bytes into the buffer using strncpy, with no check that the value fits:

DYNAMIC_STRING a_res;

if (init_dynamic_string(&a_res, NULL, 0, 0))
    goto error;
...
else if(je->value_type == JSON_VALUE_STRING)
{
    strncpy((char*)a_res.str, val.ptr(), je->value_len);
    a_res.length= je->value_len;
}

A JSON string longer than 128 bytes overflows the heap buffer. The fix replaces the strncpy with dynstr_set(), which dynamically resizes the buffer to accommodate the input.

Unlike many heap overflows, the attacker's overflow payload is constrained: the data written past the buffer boundary must consist of bytes that are valid within a JSON string. Arbitrary binary data (such as full 8-byte pointers) cannot be injected directly. This significantly limits the attacker's options — and makes the exploitation techniques described below all the more interesting.

Arbitrary write primitive

The exploit overcomes the character constraints through a combination of heap grooming and partial pointer overwrites. Rather than writing a full pointer value, the attacker corrupts only the lowest 2 bytes of an adjacent heap pointer, selecting byte values that happen to be valid JSON string characters. The key insight is that MariaDB's user-defined variables (SET @var = ...) store their values on the session's heap. Each variable has an internal user_var_entry structure that contains a value pointer to the variable's data. By carefully arranging these variables on the heap, the attacker can position the overflow buffer adjacent to a target variable's metadata, then use the 2-byte partial overwrite to redirect that variable's value pointer to a nearby controlled location.

However, the partial overwrite can only reach nearby heap addresses. It cannot directly target distant structures like thd->security_ctx or global variables. To bridge this gap, the exploit uses a two-hop write primitive built around a single SET statement:

SET @overflow_5 = CONCAT(              -- resolves overflow_5 user_var_entry BEFORE overflow
    X'...value...',                     -- write arbitrary value to *overflow_5.value
    REPEAT(
        JSON_SCHEMA_VALID(              -- triggers heap overflow into overflow_5 user_var_entry
            '{"enum":[0]}',
            '"AAAA...AA\x28\x34"'       -- 2-byte partial overwrite of overflow_5.value
        ),
        0                               -- REPEAT(..., 0) discards the return value
    )
);

The overflow and the assignment must happen in the same statement. As the diagram below shows, the overflow corrupts not just the value pointer but all preceding fields in the adjacent user_var_entry (including m_type_handler, m_charset, name.str, and name.length). After the overflow, the variable's name and type metadata are destroyed. If the attacker tried to write to @overflow_5 in a separate statement, the corrupted name and type fields would cause a crash. By embedding the overflow inside the CONCAT expression of a SET on that same variable, MariaDB resolves the variable reference before query execution (before the overflow fires), and the assignment target is already bound. The CONCAT result (the full 8-byte target address) then flows through the now-corrupted value pointer, landing in the second variable's user_var_entry.value field. A subsequent SET on that second variable writes attacker-controlled data to the final target.

Heap layout and overflow primitive diagram

Exploit steps

Stage 1: Heap grooming. The attacker allocates 66 "pad" variables of 127 bytes each to fill the heap into a predictable state. Next, 16 pairs of variables are allocated: a "free" variable (127 bytes) and an "overflow" variable (16 bytes). The free variables are then released and the overflow variables shrunk, creating 127-byte holes in the heap. When JSON_SCHEMA_VALID is called, init_dynamic_string allocates its 128-byte internal buffer, which lands in one of these holes, directly adjacent to another variable's user_var_entry.

Stage 2: Privilege escalation. The attacker uses the arbitrary write primitive to corrupt thd->security_ctx->master_access, which is at a predictable offset from the heap base. The attacker executes SET @overflow_6 = X'FFFFFFFFFFFFFFFFFF', setting all permissions bits for the session. GRANT ALL PRIVILEGES persists the privileges for the authenticated user, and SELECT ... INTO DUMPFILE /tmp/pwn.so abuses the elevated privileges to write a malicious executable to the server's disk.

Stage 3: Address leak and code execution. The attacker opens a new connection (now with full privileges) and uses LOAD DATA INFILE '/proc/1/maps' to read the process memory map into a table. Parsing the output reveals the MariaDB binary's base address, defeating PIE. The attacker then repeats the arbitrary write primitive. This time, the attacker manipulates MariaDB's global configuration: writing '/tmp' into the plugin_dir variable in the .data section. This causes MariaDB to locate plugins in /tmp, exactly where Stage 2 planted the malicious object. Finally, CREATE FUNCTION shell RETURNS STRING SONAME 'pwn.so' loads the attacker's User-Defined Function, and calling the shell function executes arbitrary shell commands as the MariaDB process user.


Responsible disclosure timeline


Final remarks

CVE-2026-32710 illustrates how even constrained memory corruption primitives — in this case, an overflow limited to valid JSON string bytes — can be chained into full remote code execution with careful heap manipulation. The exploitation required creative solutions at every stage: partial pointer overwrites to work within character constraints, single-statement write primitives to avoid crashing on corrupted metadata, and privilege escalation to bootstrap the read and write access needed for the final code execution payload.

The vulnerability sat in a built-in SQL function accessible to every authenticated session, with no privileges required beyond the ability to connect. For organizations running MariaDB, the takeaway is clear: treat every authenticated session as a potential attack surface, not just administrative connections.

This bug was found by Xint Code, an autonomous AI code analysis tool built by Theori and designed for deep vulnerability discovery across large codebases. Learn more at code.xint.io.


Stay in touch

For questions about this research, contact research@wiz.io.


References