← Volver al blog de ciberseguridad

Doce años en los que una cuenta de replicación de PostgreSQL podía cargar código en el servidor (CVE-2026-6471)

Por Thilina Manana · COO, Director Técnico de Seguridad hard2bit y socio fundador · Publicado: 07 de septiembre de 2026 · Actualizado: 07 de septiembre de 2026
PostGREShell (CVE-2026-6471)

El 13 de agosto el proyecto PostgreSQL publicó una tanda de actualizaciones que cerraba 28 vulnerabilidades. Varias tenían un CVSS de 8,8; la que ha acabado en los titulares casi tres semanas después puntúa 7,2. Es CVE-2026-6471, bautizada PostGREShell por sus descubridores, y llevaba en el código desde que la versión 9.4 estrenó la decodificación lógica en 2014.

Lo que la distingue del resto de la tanda es la premisa que rompe: una cuenta con el atributo REPLICATION, el que se concede a copias de seguridad, réplicas y conectores de datos, podía elegir qué biblioteca cargaba el servidor y, con ello, ejecutar código con la identidad del sistema operativo bajo la que corre PostgreSQL.

La cadena completa la describió Cyera Research el 1 de septiembre: de la carga de código a superusuario permanente y de ahí a una persistencia con tres mecanismos que se cubren entre sí. A fecha de 4 de septiembre no constaba explotación, no había código de prueba público y el fallo seguía fuera del catálogo KEV de CISA, según comprobó The Hacker News. Esa ventana es la que interesa aprovechar.

En Hard2bit la cuenta de replicación de PostgreSQL entró hace tiempo en el inventario de identidades no humanas que revisamos con los clientes, porque casi siempre la creó alguien que ya no está y la usan herramientas que ya no se recuerdan. Este fallo convierte esa revisión en algo urgente.

Qué se puede explotar y en qué condiciones

El aviso del proyecto es escueto: la decodificación lógica no comprobaba permisos. Un usuario con REPLICATION, sin ser superusuario, elige el módulo de decodificación y con ello obliga al servidor a cargar con dlopen() cualquier fichero que vea la cuenta del sistema operativo que ejecuta PostgreSQL. Afecta a todas las versiones anteriores a 18.6, 17.11, 16.15, 15.19 y 14.24.

Hacen falta dos condiciones simultáneas. La primera es una cuenta con el atributo REPLICATION, sin necesidad de que sea superusuario ni administrador. La segunda es que el servidor funcione con wal_level = logical, el ajuste que registra los cambios como eventos legibles por herramientas externas y que hoy es la base de la captura de cambios (CDC), de Debezium, de las migraciones a la nube y de la analítica en tiempo real.

Un programa cliente que quiere leer esos cambios crea un slot de replicación lógica, un punto de lectura persistente sobre el flujo de cambios, e indica qué módulo de salida (output plugin) debe formatear el flujo. Ese nombre viajaba directo al cargador de bibliotecas.

Cómo llega la biblioteca maliciosa hasta el cargador depende de la plataforma. En Windows basta con acceso de red: el nombre del módulo puede ser una ruta UNC y el sistema la resuelve por SMB desde un servidor del atacante, sin escribir nada en el disco de la víctima. En Linux y macOS ocurre algo parecido solo si el montaje automático de NFS está activo. En el resto de despliegues, que son la mayoría de los Linux, Docker y Kubernetes en producción, el atacante necesita haber dejado antes un fichero en el disco del servidor por otra vía.

Esa diferencia explica por qué las fuentes no coinciden en el privilegio necesario. Cyera habla de una cuenta de bajo privilegio; el proyecto PostgreSQL puntuó el fallo con privilegios requeridos altos, y SUSE reprodujo esa valoración. Las dos lecturas son defendibles. Para el modelo de permisos de PostgreSQL, REPLICATION es un atributo privilegiado. Para la organización que lo concede a una herramienta de copia de seguridad o a un conector de Kafka, es una credencial de servicio más, guardada donde se guardan las demás.

Cronología: del informe de febrero a la publicación de septiembre

  • 21 de febrero de 2026. Cyera envía al equipo de seguridad de PostgreSQL el análisis de causa raíz, las versiones afectadas y una prueba de concepto para Windows, según su cronología pública. El equipo confirma el fallo seis días después.
  • 13 de agosto. Salen 18.6, 17.11, 16.15, 15.19 y 14.24 con la corrección incluida entre las 28 vulnerabilidades del anuncio de la versión. El texto no la destaca sobre las demás. Los créditos del hallazgo son para Vladimir Tokarev y Yu Kunpeng.
  • 20 de agosto. Ubuntu publica USN-8653-1 para 22.04, 24.04 y 26.04 LTS. Como observa The Hacker News, el aviso pide reiniciar PostgreSQL tras actualizar y no menciona el nuevo parámetro de configuración.
  • 1 de septiembre. Cyera publica el análisis completo con el nombre PostGREShell. CSO Online y SecurityWeek lo recogen los días 3 y 4.
  • 4 de septiembre. The Hacker News comprueba ese día que el fallo no está en el KEV, que no hay pruebas de concepto en repositorios públicos y que el proyecto wal2json ha actualizado su documentación para indicar cómo registrar el módulo en la nueva lista de permitidos.

Un detalle de la cronología matiza la alarma: el parche llevaba diecinueve días disponible cuando se publicó el análisis. Quien mantenga al día sus versiones menores de PostgreSQL ya estaba protegido sin saberlo. El problema es que instalar el parche puede interrumpir la replicación lógica si no se prepara.

Por qué una cuenta de replicación acaba siendo superusuario

Un módulo de salida es código compilado que PostgreSQL carga dentro del proceso del servidor y cuya función de inicialización se ejecuta de inmediato con los permisos de ese proceso. El servidor ya contaba con un control para este riesgo, check_restricted_library_name(), que obliga a los usuarios sin privilegios de superusuario a cargar módulos únicamente desde un directorio controlado por el administrador, sin rutas absolutas ni saltos de directorio. El comando SQL LOAD pasa por ese control. La ruta de replicación no lo llamaba, y el analizador del protocolo admitía casi cualquier carácter dentro del nombre del módulo, separadores de ruta incluidos.

Desde ese punto el problema deja de ser de PostgreSQL y pasa a ser del modelo de cualquier servidor que carga extensiones. Las listas de control de acceso, los permisos por rol y la seguridad a nivel de fila viven en la capa SQL. El código que se carga con dlopen() comparte el espacio de memoria del servidor y no atraviesa esa capa.

En la prueba de Cyera, el módulo escribe directamente en pg_authid, el catálogo que define quién es superusuario, y activa todos los indicadores de privilegio de la cuenta. El cambio sobrevive a los reinicios y en el catálogo es idéntico a un ALTER ROLE legítimo: quien revise solo pg_authid no verá por dónde se hizo. Esa escalada de privilegios abre después las funciones habituales del superusuario: ejecutar comandos del sistema, leer ficheros del servidor y escribir donde el usuario postgres pueda.

La persistencia descrita tiene tres patas: reescribir pg_hba.conf para admitir conexiones sin contraseña y recargar la configuración, copiarse a una ruta estable y registrarse en shared_preload_libraries para volver a cargarse en cada proceso nuevo, y reaplicar el cambio de superusuario si un administrador lo revierte. Quien encuentre una de las tres y la deshaga tiene todavía dos por descubrir.

Cyera sitúa el fallo en una familia conocida: un servidor que carga módulos por nombre sin validar el nombre. Redis con MODULE LOAD, MySQL y sus bibliotecas compartidas, MongoDB, OpenVPN y el conector JDBC de SQLite han pasado por variantes del mismo patrón. La razón por la que se repite también la apunta el informe: el código que carga extensiones suele escribirse aparte del modelo de seguridad principal, y las dos rutas no siempre se conectan.

Quién está expuesto y quién menos

La exposición depende de tres preguntas, y hay que responderlas instancia por instancia, no por parque entero.

¿Cuántas cuentas tienen REPLICATION y para qué?

Las herramientas de copia física que usan el protocolo de streaming (pg_basebackup, Barman en ese modo), cada réplica en espera, cada conector CDC (Debezium y equivalentes), cada migración con servicios de nube y no pocos agentes de monitorización llevan una, y con los años se acumulan. Una consulta a pg_roles filtrando por rolreplication devuelve la lista; el trabajo consiste en poner nombre y dueño a cada entrada y quitar el atributo a las que no lo necesitan. La entrada de Hard2bit sobre cuentas de servicio, tokens y claves de API describe el mismo ejercicio para el resto de credenciales que no pertenecen a personas.

¿Está activada la decodificación lógica?

Sin wal_level = logical no hay slot lógico y no hay carga de módulo. Muchas instancias lo tienen activado por una necesidad puntual (una migración, una prueba de CDC) que terminó hace tiempo. Si nada consume cambios lógicos, volver a replica cierra la vía sin esperar al parche, a costa de un reinicio.

¿Qué puede hacer el servidor hacia fuera?

El escenario más directo es un PostgreSQL sobre Windows que puede abrir conexiones SMB salientes hacia Internet o hacia segmentos que no controla. Le sigue un Linux con autofs capaz de resolver rutas de red que el atacante controle. Fuera de esos dos casos, el fallo vuelve a ser el problema de dos pasos ya descrito: antes hay que conseguir escribir un fichero en el disco del servidor.

Los servicios gestionados no eximen del trabajo: Amazon RDS dispone de paquetes corregidos para las cinco ramas, según The Hacker News, y aun así la cuenta de replicación que alimenta un conector CDC sigue existiendo y sigue siendo responsabilidad del cliente. Y las versiones anteriores a 14 no reciben corrección; el proyecto recuerda además que PostgreSQL 14 deja de recibir parches el 12 de noviembre de 2026, con lo que cualquier instancia en 13 o inferior necesita una migración, no una actualización menor.

Detección: qué rastro deja

Es poco probable que este fallo levante alertas en el EDR del servidor hasta que el módulo cargado haga algo visible, y en la capa SQL las modificaciones parecen legítimas. El rastro está en la replicación y en el catálogo mismo. Estos son los indicadores que merecen una regla en el SIEM o una consulta programada:

  • Nombres de módulo con separadores de ruta o saltos de directorio en pg_replication_slots. La columna plugin debería contener únicamente pgoutput, test_decoding o el módulo de terceros que la organización haya instalado a sabiendas.
  • Peticiones CREATE_REPLICATION_SLOT desde direcciones que no corresponden a las réplicas ni a los conectores conocidos. Con log_connections activado, la conexión de replicación aparece en el registro con su origen.
  • Tras aplicar el parche, líneas ERROR: library "..." may not be used as an output plugin en el registro del servidor. Según la documentación del parámetro, así avisa la nueva lista de permitidos. Puede ser un conector legítimo sin registrar o un intento de carga; en ambos casos hay que mirar.
  • Cambios en pg_authid que activen rolsuper en cuentas que no lo tenían, modificaciones de pg_hba.conf que relajen la autenticación y entradas nuevas en shared_preload_libraries. Los tres elementos deberían estar bajo control de integridad.
  • Conexiones salientes del servidor de base de datos hacia los puertos 445 (SMB) y 2049 (NFS). Salvo que el servidor monte a sabiendas almacenamiento o copias por NFS o SMB, no tienen explicación operativa.

Si alguna de estas señales aparece, la prioridad es asumir que el catálogo ya no es de fiar: comparar pg_authid y pg_hba.conf con una copia de referencia íntegra, revisar qué bibliotecas hay cargadas en el proceso y rotar las credenciales que la base de datos custodia. Es el tipo de investigación que un servicio de threat hunting aborda con el catálogo y el sistema de ficheros a la vez, porque ninguno de los dos basta por separado.

Parchear sin romper la replicación

La corrección no consiste en aplicar al camino de replicación la restricción de LOAD. Jacob Champion, autor del cambio, explica en el mensaje que acompaña al commit que hacerlo habría obligado a reinstalar todos los módulos de terceros bajo el directorio de extensiones. En su lugar, el parche añade el parámetro output_plugin_libraries, una lista de módulos autorizados que por defecto solo incluye pgoutput y test_decoding, los dos que se distribuyen con PostgreSQL. Cualquier otro (wal2json, decoderbufs y los módulos desarrollados en casa) deja de cargarse tras actualizar hasta que el administrador lo añade y recarga la configuración. Las notas de la versión 18.6 lo advierten de forma expresa.

De ahí que el orden importe:

  • Antes de actualizar, inventariar los módulos en uso con SELECT DISTINCT plugin FROM pg_replication_slots WHERE plugin IS NOT NULL. La consulta solo muestra los módulos que se han usado con éxito en algún momento, así que hay que contrastarla con los equipos de datos.
  • Actualizar a 18.6, 17.11, 16.15, 15.19 o 14.24, o al paquete equivalente de la distribución. Los avisos de Debian y de Ubuntu no coinciden en el grado de detalle: Debian advierte de que la corrección exige cambios de configuración y cita sus paquetes de wal2json y decoderbufs; el aviso de Ubuntu, como se ha visto, no menciona el parámetro.
  • Añadir cada módulo de terceros a output_plugin_libraries y recargar con pg_reload_conf(). No hace falta reiniciar.
  • Si se migra desde la versión 17 o posterior con pg_upgrade, fijar el parámetro en el clúster nuevo antes de ejecutar --check, porque la comprobación falla si la lista no admite los módulos de los slots del clúster antiguo.

Hay un fleco abierto en la lista de correo de desarrollo, según recoge The Hacker News: pg_createsubscriber crea sus slots con pgoutput sin comprobar el parámetro, de modo que una ejecución con --dry-run puede superar la prueba y la conversión real fallar después si la lista del servidor no admite ese módulo. El 4 de septiembre el parche estaba en revisión y sin integrar.

Mientras no se pueda actualizar, las medidas que reducen exposición son las que Cyera recomienda y no exigen tocar la aplicación: retirar REPLICATION de las cuentas que no lo necesitan, limitar en pg_hba.conf las entradas de replicación a direcciones concretas (nunca 0.0.0.0/0), bloquear en el cortafuegos el tráfico saliente SMB y NFS desde los servidores de base de datos y desactivar autofs donde no se use. Todo ello es endurecimiento que debería sobrevivir al parche.

Qué vigilar en las próximas semanas

Hay tres cosas que vigilar. La primera, si CVE-2026-6471 entra en el KEV o aparece una prueba de concepto pública para Linux; el programa de gestión de vulnerabilidades debería tener el fallo en seguimiento aunque hoy no esté en el KEV ni haya señales públicas de explotación, con los criterios de KEV, EPSS y SSVC como referencia para subirlo de prioridad. La segunda, los escaneos contra instancias con el puerto 5432 abierto a Internet, que siguen apareciendo en las revisiones de perímetro.

La tercera, y la más importante, el resultado del inventario de cuentas con REPLICATION: ese inventario decide si este fallo es un riesgo teórico o una puerta abierta en la organización.

La semana pasada escribimos sobre la clave de unión de Artifactory, otro caso en el que una credencial de fontanería, creada para que dos componentes se hablen, acaba concediendo privilegios de administrador. En PostgreSQL el mismo patrón llevaba doce años sin revisarse. Una cuenta que solo sirve para que dos sistemas se hablen merece la misma revisión de mínimo privilegio que una de administrador, y en la mayoría de los parques que auditamos desde Hard2bit todavía no la ha tenido.

Este artículo combina información técnica de avisos públicos del proyecto PostgreSQL con la investigación publicada por Cyera Research y con las comprobaciones de The Hacker News, CSO Online y SecurityWeek, según la información disponible a fecha de publicación. Las consultas, parámetros y medidas de configuración descritas son orientativas: cada despliegue debe validarlas en un entorno de pruebas antes de aplicarlas en producción, y la lista de módulos autorizados debe ajustarse a las herramientas de cada organización. El estado de explotación y la disponibilidad de pruebas de concepto pueden cambiar.

Preguntas frecuentes

¿Qué es PostGREShell y qué versiones de PostgreSQL afecta?

PostGREShell es el nombre que Cyera Research dio a CVE-2026-6471, un fallo de autorización en la decodificación lógica de PostgreSQL. Permite que una cuenta con el atributo REPLICATION haga que el servidor cargue una biblioteca arbitraria y ejecute código con la identidad del sistema operativo del proceso. Está presente desde la versión 9.4 (2014) y se corrige en 18.6, 17.11, 16.15, 15.19 y 14.24, publicadas el 13 de agosto de 2026. Las ramas anteriores a la 14 no reciben corrección.

¿Se está explotando CVE-2026-6471?

A 4 de septiembre de 2026 no constaba explotación: el fallo no figuraba en el catálogo KEV de CISA y The Hacker News no localizó pruebas de concepto en repositorios públicos. Cyera menciona 114 módulos maliciosos de PostgreSQL hallados en VirusTotal, pero CSO Online subraya que la investigación no los vincula con este fallo. La situación puede cambiar y el CVE merece seguimiento.

¿Por qué el fallo puntúa 7,2 si permite ejecutar código y ser superusuario?

El vector CVSS asignado por el proyecto PostgreSQL considera altos los privilegios requeridos: hace falta una cuenta con REPLICATION. Además, el servidor debe funcionar con wal_level = logical. Cyera lo describe como una cuenta de bajo privilegio porque en la práctica se entrega a herramientas de copia de seguridad y conectores. El impacto, una vez cumplidas las condiciones, es completo en confidencialidad, integridad y disponibilidad.

¿Mi PostgreSQL está expuesto si corre en Linux o en Kubernetes?

Con menos facilidad que en Windows. Fuera de Windows y de un Linux con autofs capaz de resolver rutas de red ajenas, el atacante necesita haber dejado antes un fichero en el disco del servidor, así que el fallo funciona como segundo paso de una intrusión y no como el primero. Eso rebaja la urgencia en un clúster de Kubernetes bien aislado, pero no la elimina: un contenedor con un volumen compartido escribible o una aplicación con una vulnerabilidad de subida de ficheros aportan justo ese primer paso.

¿Qué cambia al actualizar y por qué puede romper la replicación lógica?

Que wal2json, decoderbufs y los módulos desarrollados en casa dejan de cargarse hasta que se registran en output_plugin_libraries y se recarga la configuración, sin reinicio. El efecto práctico es que un conector de captura de cambios que funcionaba el día anterior se detiene tras la actualización con un error en el registro del servidor, y el equipo de datos lo nota antes que el de seguridad. Inventariar los módulos antes de actualizar evita esa sorpresa; el proyecto wal2json ya documenta el paso.

¿Cómo compruebo qué cuentas tienen el atributo REPLICATION?

Consultando la vista pg_roles y filtrando por rolreplication = true. La lista suele incluir la cuenta de la herramienta de copias, la de las réplicas en espera, la de los conectores de captura de cambios y, con frecuencia, cuentas de pruebas o migraciones antiguas. A cada una hay que asignarle un dueño y un uso; a las que no tienen dueño o no tienen uso se les retira el atributo. En pg_hba.conf, cada cuenta que conserve REPLICATION debería conectarse solo desde direcciones concretas.

¿Qué puedo hacer si no puedo actualizar PostgreSQL todavía?

Reducir las dos condiciones que el fallo necesita. Sobre las cuentas: menos usuarios con REPLICATION y, para los que queden, entradas de pg_hba.conf cerradas por dirección de origen. Sobre la carga de la biblioteca: cortafuegos de salida para los puertos 445 y 2049 y autofs apagado, de modo que el servidor no pueda traerse un fichero de fuera. Y si ninguna herramienta consume cambios lógicos, devolver wal_level a replica elimina la condición de partida, a costa de un reinicio.

¿Afecta a los servicios gestionados como Amazon RDS o Azure Database?

El motor lo actualiza el proveedor, pero la responsabilidad se reparte. La numeración de versiones de un servicio gestionado no siempre coincide con la del proyecto, así que hay que comprobar en las notas del proveedor que su paquete incorpora la corrección de CVE-2026-6471, y no dar por hecho que la última versión disponible la incluye. Y las cuentas con REPLICATION que el cliente creó para alimentar conectores hacia Kafka o hacia un almacén analítico las revisa el cliente, no el proveedor.

¿Quieres saber cuál es tu exposición real y qué corregir primero?

Treinta minutos con un consultor técnico —no un comercial— bastan para ordenar el problema: qué está expuesto hoy, qué se corrige esta semana, qué puede esperar y cuánto cuesta cada tramo. Pentesting, auditoría de ciberseguridad, gestión de vulnerabilidades, Microsoft 365, SOC/MDR y respuesta a incidentes.

Si tu situación es distinta, plantéanosla igualmente: también atendemos consultas puntuales de ciberseguridad y cumplimiento normativo.

Empresa española de ciberseguridad · ENS categoría ALTA · ISO 27001 · Normalmente respondemos en menos de 24h laborables