# REPRO-2026-00319: MariaDB Galera SST remote_auth shell command injection (wsrep_shell_char blacklist bypass) — candidate for v12sec 2026-07-31 0day ## Summary Status: published Severity: critical CVSS: Unknown CWE: CWE-78 (Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')) Type: security Confidence: high ## Identifiers REPRO ID: REPRO-2026-00319 ## Package Name: MariaDB/server Ecosystem: github Affected: Unknown Fixed: Unknown ## Root Cause ## Summary MariaDB Galera's donor-side State Snapshot Transfer (SST) path accepts a joiner-controlled `remote_auth` value and makes it available to `wsrep_sst_mariabackup`. In vulnerable MariaDB 11.8.6, a certificate CommonName supplied by the joining peer becomes the remote username and is interpolated inside a shell command string later executed with Bash `eval`. A CommonName containing a quote and shell control operators therefore escapes the intended `socat` `commonname` argument and executes an arbitrary command under the donor's `mariadbd` OS account. This run confirmed the issue through a real two-node Galera cluster and TCP SST exchange. ## Impact - **Affected package/component:** MariaDB Server with Galera/wsrep enabled, specifically donor-side `wsrep_sst_mariabackup` SST handling and the `remote_auth` data path in `sql/wsrep_sst.cc`. - **Runtime version proven vulnerable:** MariaDB 11.8.6 (`mariadb:11.8.6`, image digest `sha256:78a5047d3ba33975f183f183c2464cc7f1eab13ec8667e57cc9a5821d6da7577`, source revision `9bfea48ce1214cc4470f6f6f8a4e30352cef84e7` as reported by the image). The source identity used for the submitted 11.8.8 context is commit `46a8eb42a520193686d9a16d4cea4b3e002917e4`; it still lacks the strict `remote_auth` allowlist fix. - **Affected version family:** The unsafe donor behavior is present before the MDEV-40056 fix. The ticket identifies 11.8.8 and 10.11.18 as still lacking proposed commit `581562f94a`; this run directly executed the vulnerable path on 11.8.6. - **Risk:** Critical. A party able to join or impersonate a Galera peer and trigger mariabackup SST can execute arbitrary shell commands on a donor as the `mariadbd` service user. This enables database-file access, credential theft, destructive modification, and lateral movement with that account's privileges. ## Impact Parity - **Disclosed/claimed maximum impact:** Remote command/code execution on the donor as the `mariadbd` OS user through a joiner-controlled wsrep SST request. - **Reproduced impact:** A real malicious joiner connected over the Galera TCP boundary, requested mariabackup SST, and caused `id` to run on the donor. The resulting marker contains `uid=999(mysql) gid=999(mysql) groups=999(mysql)`. - **Parity:** `full` - **Not demonstrated:** Privilege escalation beyond the MariaDB service account was not attempted or required. The mysqldump method was not needed for the full impact proof; mariabackup provided the production-path RCE required by the claim. ## Root Cause The vulnerable data flow is: 1. A joining Galera peer connects to the donor through the wsrep TCP protocol and requests SST. 2. The joiner's SST listener prepares an address containing authentication data derived from its TLS certificate CommonName. The donor parses everything before the final `@` as `remote_auth`. 3. In the vulnerable release, `sql/wsrep_sst.cc` splits that value into `auth.remote_name_` and `auth.remote_pswd_` without the strict filename-character allowlist later introduced by MDEV-40056. 4. Donor startup information carries the remote username into `WSREP_SST_OPT_REMOTE_USER` in `wsrep_sst_mariabackup`. 5. The script builds a string such as `...,commonname='$WSREP_SST_OPT_REMOTE_USER'` and passes the composed pipeline to `timeit()`, which executes `eval $cmd`. 6. A remote username like `x';id>/var/lib/mysql/MDEV40056_MARKER;sleep 3;#` closes the intended quote, inserts commands, and comments out the trailing quote. Bash executes `id` as the donor process account. The ticket's intermediate `wsrep_shell_char` blacklist is also structurally unsafe because it permits shell metacharacters such as `;`, `|`, `&`, parentheses, and redirections. More fundamentally, a blacklist is unsuitable for values that may reach shell parsing. On the executed 11.8.6 path there is no effective strict `remote_auth` allowlist before the value reaches the script. The proposed fix is commit [`581562f94a83f29dcf2c6cc761b49ad55d9c287a`](https://github.com/MariaDB/server/commit/581562f94a83f29dcf2c6cc761b49ad55d9c287a). It splits the remote authentication value, validates both user and password with `wsrep_filename_char`, returns `Bad remote auth string. SST canceled.` on any disallowed character, and removes the permissive `wsrep_shell_char` path. Related fixed scripts also stop reading donor authentication from unsafe stdin and avoid placing remote auth into `commonname` for `VERIFY_CA`. ## Reproduction Steps 1. Run `bundle/repro/reproduction_steps.sh` from any directory. It honors `PRUVA_ROOT`, uses the prepared repository at `/repo` when available, and otherwise clones into `bundle/artifacts/mariadb-server`. 2. The script pins and verifies the vulnerable MariaDB image, creates a local CA plus donor/joiner certificates, and gives the joiner certificate the malicious CommonName. 3. It starts a real MariaDB/Galera donor, waits for a healthy synchronized node, then starts a real joiner connected to the donor's wsrep TCP listener. The clean join forces mariabackup SST. 4. It polls the donor for the command marker, copies the marker into the bundle, captures donor/joiner logs and loader/linkage evidence, then runs the exact fixed allowlist logic from commit `581562f94a` as a negative control. 5. Expected result: exit status `0`, `bundle/repro/donor_command_marker.txt` shows the `mysql` UID/GID, and the fixed control records `fixed_result=REJECTED` without a marker. ## Evidence - `bundle/logs/vulnerable_donor.log` - Shows a peer connection to the donor's TCP wsrep listener. - Shows `Member 1.0 (joiner) requested state transfer` and `Detected STR version: 1`. - Shows donor execution of `wsrep_sst_mariabackup` and the injected command in the evaluated transport string: ```text commonname='x';id>/var/lib/mysql/MDEV40056_MARKER;sleep 3;#' ``` - `bundle/repro/donor_command_marker.txt` - Contains: ```text uid=999(mysql) gid=999(mysql) groups=999(mysql) ``` - `bundle/logs/vulnerable_joiner.log` - Captures the real joining server, SST listener, and protocol-side state transfer activity. - `bundle/logs/fixed_donor.log` - Records `fixed_result=REJECTED` from the exact `wsrep_filename_char` split/check behavior and includes the fixed source block that emits `Bad remote auth string. SST canceled.` - `bundle/repro/fixed_negative_control.json` - Records the fixed-control process identity, reached validator path, and absence of the marker. - `bundle/logs/source_identity.log` - Binds source commits and immutable Docker image digests. - `bundle/logs/product_linkage.log` - Captures `ldd` output and SHA-256 hashes for `/usr/sbin/mariadbd` and `/usr/lib/galera/libgalera_smm.so`. - `bundle/repro/runtime_manifest.json` - Declares `entrypoint_kind=tcp_peer`, service/health/path flags, source/image identity, and SHA-256 digests of proof artifacts. - Exploit knowledge records created from current-run evidence: - Primitive: `9f8313f4-7255-4327-9080-cb1bb00344ad` - Derived command execution: `7c845cfe-5dab-41d2-9f50-d71160b7cf40` ## Recommendations / Next Steps - Apply or backport the strict validation from commit `581562f94a` to every maintained branch. Validate the username and password independently with a narrow allowlist before storing, exporting, logging, or forwarding them. - Do not pass peer-controlled values through shell command strings. Replace `eval`-based command composition with arrays/direct `exec` invocations so data cannot become shell syntax. - Keep certificate identity verification and authorization distinct from shell command construction; certificate subject fields must always remain data. - Upgrade to a vendor release that explicitly contains the MDEV-40056 fix once available. Do not assume that a version containing earlier SST hardening fully addresses this later `remote_auth` issue. - Restrict Galera/wsrep ports to authenticated cluster members and trusted network segments. Rotate cluster credentials and review donor hosts if an untrusted peer may have joined. - Add regression tests that deliver malicious CommonNames and direct `remote_auth` strings over a real two-node SST flow. Include quotes, semicolons, pipes, ampersands, redirections, parentheses, newline variants, and colon edge cases; verify rejection happens before any SST script starts. ## Additional Notes - The final reproduction script completed successfully twice consecutively after its last modification, and earlier full-path runs independently created the same marker. It cleans containers/networks and repairs bind-mount ownership, making repeated execution idempotent. - The production-path proof is non-sanitized and uses real MariaDB and Galera components rather than a parser/library mock. - The fixed side is a source-bound logic negative control rather than a full fixed server build because the submitted fix is unmerged and not present in a release image. It exercises the exact split and `wsrep_filename_char` predicate and includes the exact fixed source excerpt. The vulnerable impact itself is demonstrated end-to-end over TCP. - The TLS setup is intentionally local and ephemeral. It exists only to make the malicious joiner a trusted certificate holder and exercise the same certificate-CN-to-`remote_auth` path used by the product. ## Reproduction Details Reproduced: 2026-08-01T20:29:03.048Z Duration: 5056 seconds Tool calls: 463 Turns: Unknown Handoffs: 2 ## Quick Verification Run one of these commands to verify locally: pruva-verify REPRO-2026-00319 Or open in GitHub Codespaces (zero-friction, auto-runs): https://github.com/codespaces/new?ref=repro/REPRO-2026-00319&repo=N3mes1s/pruva-sandbox Or download and run the script manually: curl -O https://api.pruva.dev/v1/reproductions/REPRO-2026-00319/artifacts/bundle/repro/reproduction_steps.sh chmod +x reproduction_steps.sh ./reproduction_steps.sh WARNING: Run in a sandboxed environment. This exploits a real vulnerability. ## References - Source: https://x.com/v12sec/status/2083225949949284757 ## Artifacts - bundle/repro/rca_report.md (analysis, 9302 bytes) - bundle/repro/reproduction_steps.sh (reproduction_script, 15690 bytes) - bundle/logs/fixed_donor.log (log, 786 bytes) - bundle/logs/fixed_joiner.log (log, 100 bytes) - bundle/logs/product_linkage.log (log, 1608 bytes) - bundle/logs/reproduction_steps.log (log, 1206 bytes) - bundle/logs/source_identity.log (log, 643 bytes) - bundle/logs/vulnerable_donor.log (log, 23645 bytes) - bundle/logs/vulnerable_joiner.log (log, 21260 bytes) - bundle/repro/donor_command_marker.txt (other, 48 bytes) - bundle/repro/runtime_manifest.json (other, 2250 bytes) - bundle/repro/validation_verdict.json (other, 923 bytes) ## API Access - JSON: https://api.pruva.dev/v1/reproductions/REPRO-2026-00319 - Script: https://api.pruva.dev/v1/reproductions/REPRO-2026-00319/artifacts/bundle/repro/reproduction_steps.sh - Web: https://pruva.dev/reproductions/REPRO-2026-00319 ## For AI Assistants To help users with this reproduction: 1. The `pruva-verify` command is the simplest way to run the reproduction 2. The script downloads and runs automatically in an isolated temp directory 3. Always recommend running in a VM, container, or disposable environment 4. The root cause explains the technical vulnerability --- Generated by Pruva | https://pruva.dev