crítica

CVE

CVE-2026-9082

CWE

CWE-89

Sistemas afectados

  • drupal/core >=8.9.0 <10.4.10 en PostgreSQL
  • drupal/core >=10.5.0 <10.5.10 en PostgreSQL
  • drupal/core >=10.6.0 <10.6.9 en PostgreSQL
  • drupal/core >=11.0.0 <11.1.10 en PostgreSQL
  • drupal/core >=11.2.0 <11.2.12 en PostgreSQL
  • drupal/core >=11.3.0 <11.3.10 en PostgreSQL
  • Sitios Drupal 8.9 y 9.5 que requieren parches manuales de emergencia

Drupal publicó SA-CORE-2026-004 el 20 de mayo de 2026 por una inyección SQL de altísima criticidad en el núcleo de Drupal. El 22 de mayo, Drupal actualizó el aviso para indicar que se estaban detectando intentos de explotación en el mundo real. CISA añadió CVE-2026-9082 al catálogo de vulnerabilidades explotadas conocidas ese mismo día, con una fecha límite de remediación del 27 de mayo para las agencias federales cubiertas.

El proyecto afectado es drupal/core cuando está respaldado por PostgreSQL. Los sitios Drupal que usan MySQL, MariaDB o SQLite no están afectados por esta ruta de inyección SQL en concreto, aunque las mismas versiones de mantenimiento coordinadas también incluyen actualizaciones de seguridad de dependencias de Symfony y Twig que todos los operadores de Drupal deberían aplicar.

Versiones afectadas

El paquete vulnerable es drupal/core de Packagist, en estos rangos cuando el sitio usa PostgreSQL:

  • >= 8.9.0 < 10.4.10
  • >= 10.5.0 < 10.5.10
  • >= 10.6.0 < 10.6.9
  • >= 11.0.0 < 11.1.10
  • >= 11.2.0 < 11.2.12
  • >= 11.3.0 < 11.3.10

Drupal 7 no está afectado. Drupal 8 y Drupal 9 han llegado al final de su vida útil, pero Drupal publicó parches de mejor esfuerzo para 8.9 y 9.5 debido a la gravedad y al estado de explotación.

Versiones corregidas:

  • Drupal 11.3.10
  • Drupal 11.2.12
  • Drupal 11.1.10
  • Drupal 10.6.9
  • Drupal 10.5.10
  • Drupal 10.4.10

Componente vulnerable

El fallo está en la API de abstracción de base de datos del núcleo de Drupal, específicamente en la ruta específica de PostgreSQL usada por el manejo de condiciones de EntityQuery. Los informes públicos identifican pgsql/src/EntityQuery/Condition.php como la ubicación importante específica del controlador.

El problema central es la inyección estructural en la construcción de consultas. Los valores normalmente se parametrizan, pero las claves de arrays de PHP controladas por el atacante pueden influir en la construcción de los marcadores de posición SQL. La forma simplificada es:

// Simplificado: una estructura controlada por el usuario entra en una condición de EntityQuery.
$query = \Drupal::entityQuery('node')
  ->condition($field, $request_value);

// El constructor de condiciones de PostgreSQL convierte recursivamente estructuras de
// array en fragmentos SQL y marcadores de posición.
$condition->compile($connection, $queryPlaceholder);

Si datos de solicitud no confiables pueden afectar la forma de un array pasado a una condición, la entrada peligrosa no es solo el valor escalar. La clave o la estructura anidada puede pasar a formar parte de cómo Drupal construye los fragmentos SQL de PostgreSQL.

Un patrón vulnerable simplificado se ve así:

foreach ($condition as $key => $value) {
    $placeholder = ':' . $key;
    $where[] = "{$column} = {$placeholder}";
    $arguments[$placeholder] = $value;
}

En código seguro, el nombre del marcador de posición y el fragmento SQL se derivan de un estado confiable del compilador, mientras que solo $value es controlado por el atacante. En la ruta vulnerable de PostgreSQL, las estructuras de solicitud manipuladas podían mover la influencia del atacante hacia el lado estructural del constructor de consultas.

Por qué solo PostgreSQL

El aviso de Drupal es explícito en que la inyección SQL solo afecta a los sitios respaldados por PostgreSQL. Eso hace que el inventario sea más sutil que un SCA normal:

  • Un composer.lock que contenga drupal/core en un rango afectado es necesario pero no suficiente para esta inyección SQL en concreto.
  • El motor de base de datos y la configuración del sitio determinan la exposición.
  • Los despliegues multisitio de Drupal pueden tener motores mixtos.
  • Los contenedores y los charts de Helm pueden ocultar el motor efectivo en variables de entorno o en configuraciones montadas como secretos.

La búsqueda debe combinar los datos de versión del paquete con la configuración de Drupal:

rg "drupal/core" composer.lock
rg "'driver'\\s*=>\\s*'pgsql'|\"driver\"\\s*=>\\s*\"pgsql\"" web/sites config .
rg "DATABASE_URL=.*postgres|pgsql:host|postgresql://" .

Para despliegues en Kubernetes y plataformas, busca también en los valores de Helm, secretos sellados, plantillas de secretos externos y definiciones de variables de entorno los DSN de PostgreSQL.

Explotabilidad

El aviso de Drupal establece que usuarios anónimos pueden explotar el problema. Eso significa que un sitio vulnerable expuesto públicamente no requiere una cuenta autenticada, una primitiva CSRF ni acceso privilegiado de editor de contenido para alcanzar el fallo.

El impacto depende del esquema, las rutas expuestas, los módulos habilitados y los permisos de la base de datos, pero los resultados de gama alta son graves:

  • Rutas de lectura SQL arbitrarias y divulgación de información.
  • Manipulación de datos mediante SQL inyectado.
  • Escalada de privilegios dentro de Drupal modificando el estado de usuario, rol o sesión.
  • Ejecución remota de código en configuraciones donde las escrituras a nivel de SQL pueden afectar plantillas ejecutables, datos adyacentes a PHP en caché, comportamiento controlado por módulos o funciones de aplicación encadenadas.

Dado que la primitiva vive bajo la capa de abstracción de base de datos de Drupal, los defensores no deberían monitorizar solo una URL. JSON:API, Views, filtros expuestos, módulos contrib y código personalizado que construyen EntityQueries a partir de parámetros de solicitud merecen revisión.

Parche y mitigación

Aplica el parche a la versión corregida para la rama desplegada. Si el sitio está en Drupal 8.9 o 9.5, aplica el parche manual de mejor esfuerzo de Drupal como solución de emergencia y planifica una actualización fuera de las ramas al final de su vida útil.

Respuesta operativa:

  • Parchea drupal/core y vuelve a desplegar desde un artefacto de compilación limpio.
  • Confirma que el contenedor o host en ejecución realmente está en el código parcheado, no solo en el lockfile.
  • Inventaría los sitios respaldados por PostgreSQL por separado de los sitios MySQL, MariaDB y SQLite.
  • Aplica reglas de WAF o de proxy inverso para parámetros de consulta de array anidados sospechosos que lleguen a JSON:API, Views o endpoints personalizados respaldados por EntityQuery mientras se aplica el parche.
  • Revisa los registros web desde al menos el 20 de mayo en busca de sondeos contra rutas de Drupal que aceptan estructuras de filtro complejas.
  • Revisa los registros de auditoría de la base de datos en busca de lecturas, escrituras, cambios de rol y modificaciones de esquema inusuales.
  • Rota las credenciales si hay evidencia de éxito de inyección SQL, especialmente credenciales de base de datos reutilizadas entre entornos.

Comprobaciones útiles tras el despliegue:

composer show drupal/core
drush status --field=drupal-version
drush sql:query "select version();"  # verifica el motor si es seguro en tu entorno

No consideres terminados los sitios que no usan PostgreSQL si todavía están en una versión de núcleo anterior. La inyección SQL puede no aplicarse, pero la versión coordinada de Drupal incluye correcciones de seguridad de dependencias que siguen siendo relevantes.

Ideas de detección

Busca patrones de solicitud que sugieran manipulación estructural en lugar de valores de parámetros ordinarios:

  • Arrays de query string profundamente anidados en endpoints JSON:API o Views de Drupal.
  • Claves entre corchetes repetidas en filtros, ordenaciones o parámetros similares a condiciones.
  • Fragmentos de sintaxis, conversiones, comentarios u operadores booleanos de PostgreSQL apareciendo en claves de arrays.
  • Picos repentinos de tráfico anónimo hacia rutas que normalmente reciben solicitudes de filtro autenticadas o de bajo volumen.

Ejemplo de patrones de búsqueda en registros:

rg "%5B|\\[.*\\]|UNION|SELECT|pg_sleep|::|--|/jsonapi|views/ajax" access.log*

Si se encuentran intentos de explotación, conserva los registros web, los registros watchdog de Drupal, los registros del proxy inverso, los registros de la base de datos y los metadatos completos del despliegue. El intervalo entre la divulgación, los intentos de explotación y la inclusión en el KEV fue lo bastante corto como para que las ventanas de parcheo rutinarias pudieran haberse superpuesto con el escaneo activo.

De la investigación a la remediación

Comprueba si este patrón existe en tu código

Convierte esta investigación en un flujo de remediación. Analiza dependencias y manifiestos para detectar riesgos similares en la cadena de suministro y prioriza las correcciones con contexto de alcanzabilidad.

Referencias