El cuco no construye nido: pone su huevo en el de otro pájaro, que lo incuba y alimenta como si fuera suyo. Nadie comprueba qué hay dentro del huevo, sólo que está en el nido. Pues algo así le ha pasado a PostgreSQL durante 22 años: unos bytes que se colocaron como un tipo de dato y que, tiempo después, el servidor leyó como si fueran otro.
Mehmet Ince lo cuenta en la tercera parte de una serie de seis sobre los riesgos del Postgres gestionado. El fallo es el CVE-2026-6460, con una puntuación CVSS de 8,8, y basta con un usuario con permisos mínimos para tumbar el servidor y, según el autor, llegar a ejecutar código.
Qué pasa
La idea, sin entrar en el detalle del exploit, es sencilla de contar:
- Se crea un tipo compuesto (un tipo de fila, con sus atributos) y se prepara una sentencia que construye un valor de ese tipo con un atributo
uuid. - Con
ALTER TYPEse cambia el tipo de ese atributo a otro distinto. - La sentencia preparada sigue usando los bytes antiguos, que nadie ha reescrito, pero ahora el servidor los interpreta con el tipo nuevo.
Si el tipo nuevo es bytea, la función que lo convierte a texto interpreta esos bytes como un puntero a un “objeto expandido” (una representación en memoria que Postgres usa para trabajar con valores grandes) y llama a sus métodos. Con un puntero nulo, el proceso cae. Con la misma confusión aplicada a un array, se puede sacar una dirección de memoria como si fuera un número. Y con las dos cosas juntas, el autor explica que se puede redirigir esa llamada y acabar ejecutando comandos del sistema.
¿Por qué 22 años? Porque la posibilidad de cambiar el tipo de una columna llegó en un commit del 5 de mayo de 2004. Los objetos expandidos, que son los que convierten la confusión en algo explotable, llegaron en 2015. Dos piezas razonables cada una por su lado que, juntas, abren la puerta.
Lo de los proveedores gestionados
Lo que más me ha llamado la atención no es el fallo en sí, sino la frase del autor: “no he visto ningún proveedor que no esté afectado”. Lo descubrió a principios de agosto y avisó en privado a Databricks, Google (AlloyDB), Supabase, AWS (Aurora y RDS), Azure, Ubicloud y ClickHouse. Algunos aplicaron mitigaciones propias antes de que saliera el parche oficial.
En un Postgres gestionado no eres superusuario: el proveedor te da un rol con permisos recortados precisamente para que no puedas salir de tu base de datos al sistema. Un fallo que sólo necesita un usuario normal para ejecutar código se salta esa frontera, y en un servicio compartido eso es lo peor que puede pasar.
La serie tiene más miga. La primera parte va de una corrupción de memoria en address_standardizer, una extensión que viene con PostGIS, explotada en NeonDB, Supabase y Xata. Su tesis es que no existe un sandbox para las extensiones: un fallo de memoria en una extensión es un fallo de memoria en el propio servidor, y como todos los proveedores ofrecen las mismas extensiones, un único fallo afecta a muchas empresas a la vez. Para los que trabajamos con datos geoespaciales, PostGIS no es un extra opcional, así que esto toca de cerca.
Qué hay que hacer
Actualizar. Las versiones corregidas se han publicado esta semana:
| Rama | Versión corregida |
|---|---|
| 18 | 18.7 |
| 17 | 17.12 |
| 16 | 16.16 |
| 15 | 15.20 |
| 14 | 14.25 |
La 13 y anteriores ya no reciben parches, así que si sigues en alguna de ellas, toca migrar. Y no es una actualización sólo por este fallo: el anuncio incluye más de 40 CVE, varios con puntuación 8,8 (otra confusión de tipos en PL/pgSQL, un use-after-free en dblink, la replicación lógica escribiendo en el catálogo del suscriptor…). Para saber en qué versión estás:
SELECT version();
Si usas un servicio gestionado, lo normal es que el proveedor lo aplique por ti, pero conviene comprobar que la versión menor ha subido y no darlo por hecho. Y si tienes un Postgres propio con usuarios en los que no confías del todo (aplicaciones de terceros, entornos compartidos, cuentas de análisis…), no esperes a la próxima ventana de mantenimiento.
Me quedo con la reflexión de fondo de la serie: hemos convertido Postgres en la base de datos por defecto de medio mundo, con docenas de proveedores que lo ofrecen como servicio y con las mismas extensiones en todos ellos. Eso es estupendo hasta que aparece un fallo como este, que no está en un proveedor concreto sino en el código que comparten todos.




