Omisión de autenticación en el proxy WebSocket de Echo (GHSA-cxf3-9h37-7rr8)
Las actualizaciones WebSocket rechazadas mediante el middleware Proxy de Echo dejan abierto un túnel directo al servidor de destino. Las solicitudes HTTP posteriores por esa conexión eluden el enrutador y el middleware de rutas de Echo, omitiendo la autenticación aplicada solo en sus rutas. GitHub Advisory Database lo califica como crítico, CVSS v4.0 9.1, mientras que el aviso de Echo lo considera moderado. Corregido en v4.16.1 y v5.4.1, publicadas el 22 de octubre de 2026. No se conocen pruebas de concepto públicas ni explotación en ataques reales.
Resumen
- Cuando un cliente solicitaba una actualización WebSocket en una ruta gestionada por el middleware Proxy de Echo, las versiones anteriores tomaban el control de la conexión del cliente y se conectaban directamente al servidor de destino, copiando bytes en ambos sentidos sin leer nunca su respuesta. Si ese servidor rechazaba la actualización con una respuesta HTTP normal y mantenía la conexión activa, el túnel quedaba abierto.
- Cualquier solicitud HTTP posterior que el atacante enviara por esa misma conexión se remitía directamente al servidor de destino. El enrutador y el middleware de rutas de Echo, donde la mayoría de las aplicaciones aplican la autenticación y la autorización, nunca la veían.
- La revisión de GitHub Advisory Database califica el problema como crítico, CVSS v4.0 9.1; los responsables de Echo califican su propio aviso como moderado. Se registran CWE-444 y CWE-863. No figura en el catálogo KEV, no existe ningún exploit público y no se conoce explotación en ataques reales a fecha del 24 de octubre de 2026.
- Actualice a v4.16.1 o posterior en la rama v4, o a v5.4.1 o posterior en v5. Hasta entonces, rechace las solicitudes de actualización WebSocket antes de que lleguen a las rutas del proxy, o aplique autorización independiente en el servidor de destino.
¿Estoy afectado?
Está afectado si se cumplen todas estas condiciones:
- Su aplicación o puerta de enlace de API utiliza Echo, el módulo
github.com/labstack/echo/v4en la versión 4.16.0 o anterior, ogithub.com/labstack/echo/v5en la versión 5.4.0 o anterior. - Una ruta o grupo utiliza el middleware Proxy integrado de Echo (
middleware.Proxy,ProxyWithConfigo las funciones auxiliares del balanceador), de modo que Echo reenvía solicitudes a un servidor de destino. - Un cliente puede acceder a esa ruta del proxy y solicitar una actualización WebSocket en ella.
- Los controles de seguridad de los recursos del servidor de destino residen en las rutas o el middleware de Echo, en lugar de en el propio servidor.
No está afectado si nunca monta el middleware Proxy: el enrutamiento normal de Echo, el middleware de autenticación, el servicio de archivos estáticos y las demás funciones quedan fuera de este error. La omisión tampoco permite al atacante acceder a ningún host distinto del servidor de destino configurado en el proxy, ni derrota la autenticación propia de ese servidor. pkg.go.dev enumera 32.160 paquetes que importan github.com/labstack/echo/v4 (consultado el 24 de octubre de 2026), y solo está expuesto el subconjunto que monta el middleware Proxy.
| Rama | Versiones afectadas | Versión corregida |
|---|---|---|
| echo/v4 | >= 4.0.0, < 4.16.1 | 4.16.1 |
| echo/v5 | >= 5.0.0, < 5.4.1 | 5.4.1 |
El aviso menciona reproducciones en tiempo de ejecución que confirman v4.15.0, v4.16.0, v5.0.0 y v5.4.0, y señala que el historial del código muestra la ausencia de validación desde v4.0.0.
Compruebe sus módulos y sus versiones:
go list -m github.com/labstack/echo/v4
go list -m all | grep labstack/echo
govulncheck ./...
# In a Docker image that has the module cache
docker run --rm <image> sh -c "go list -m github.com/labstack/echo/v4 2>/dev/null || grep labstack/echo /go.mod"
# Directly in the build files
grep -rn "labstack/echo" go.mod go.sum
govulncheck señala el intervalo de versiones afectado por este aviso cuando el módulo figura en el grafo de compilación.
¿Cómo lo corrijo?
Actualice el módulo:
go get github.com/labstack/echo/v4@v4.16.1
# or, on the v5 line
go get github.com/labstack/echo/v5@v5.4.1
go mod tidy
Tenga en cuenta el requisito de v4.16.1: las dependencias corregidas de golang.org/x/ necesitan Go 1.26 o posterior, por lo que quizá también deba actualizar sus herramientas de compilación. Las versiones de mantenimiento posteriores, como v4.16.2 publicada el 23 de octubre de 2026, incluyen la misma corrección y mejoras adicionales; por tanto, también sirve fijar la versión de mantenimiento más reciente de su rama.
Si no puede actualizar inmediatamente, el aviso ofrece dos medidas provisionales y destaca una medida que no funciona:
- Rechace las solicitudes de actualización WebSocket antes de que alcancen las rutas de proxy afectadas. Un pequeño middleware delante del proxy que responda a los intentos de actualización con un error normal cierra el punto de entrada.
- Aplique autorización de forma independiente en cada recurso del servidor de destino, para que las solicitudes que eludan la capa de rutas de Echo sigan encontrando controles reales.
- Devolver simplemente una respuesta distinta de 101 desde el servidor de destino no ayuda, porque ese rechazo es precisamente lo que deja abierto el túnel vulnerable.
Los límites son claros: la primera medida desactiva por completo el proxy WebSocket y la segunda solo protege los recursos que tienen sus propios controles, algo que la aplicación debe verificar recurso por recurso.
¿Cuál es la causa raíz?
El middleware Proxy de Echo elegía un túnel de bytes sin procesar para las solicitudes WebSocket antes de comprobar si el servidor de destino aceptaba la actualización; por eso, el túnel seguía funcionando después de que el servidor la rechazara.
La selección, en middleware/proxy.go de v4.16.0, línea 391:
// Proxy
switch {
case c.IsWebSocket():
proxyRaw(tgt, c, config).ServeHTTP(res, req)
default: // even SSE requests
proxyHTTP(tgt, c, config).ServeHTTP(res, req)
}
El problema está en proxyRaw (línea 134). Toma el control de la conexión del cliente, se conecta al servidor de destino y copia bytes en ambas direcciones:
in, _, err := c.Response().Hijack()
...
out, err := dialFunc(c.Request().Context(), "tcp", t.URL.Host)
...
// Write header
err = r.Write(out)
...
errCh := make(chan error, 2)
cp := func(dst io.Writer, src io.Reader) {
_, copyErr := io.Copy(dst, src)
errCh <- copyErr
}
go cp(out, in)
go cp(in, out)
Observe lo que falta: r.Write(out) envía la solicitud de actualización y luego dos bucles io.Copy trasladan bytes indefinidamente, pero nada lee la respuesta HTTP del servidor de destino a la solicitud de actualización, ni condiciona el túnel a que el servidor responda 101 Switching Protocols. Compárelo con proxyHTTP, la rama que no corresponde a WebSocket, que delega en httputil.NewSingleHostReverseProxy de Go, un componente que sí valida las respuestas del servidor de destino.
Las consecuencias se derivan directamente. Una vez que se toma el control de la conexión del cliente, termina la gestión de solicitudes de Echo para esa conexión. Si el servidor de destino responde al intento de actualización con una respuesta HTTP normal y, de forma decisiva, mantiene activa la conexión TCP mediante HTTP keep-alive, el bucle de copia sin procesar sigue reenviando datos. El cliente recibe los bytes del rechazo del servidor y puede enviar otra solicitud HTTP normal por la misma conexión. cp(out, in) la escribe literalmente en el servidor de destino, y la respuesta vuelve por el mismo camino. Para esas solicitudes se eluden el enrutador, el middleware de rutas, los límites de frecuencia y la autenticación a nivel de ruta de Echo, porque, desde su punto de vista, la conexión salió del mundo HTTP cuando se tomó su control.
¿Cómo se explota?
No existe ninguna prueba de concepto pública. El aviso, publicado por el responsable vishr y que reconoce al informante @Duodum, describe el mecanismo e indica que los responsables reprodujeron el flujo en tiempo de ejecución en v4.15.0, v4.16.0, v5.0.0 y v5.4.0. La ruta de ataque descrita es la siguiente:
- El atacante abre una conexión a una ruta de Echo que utiliza el middleware Proxy y envía una solicitud HTTP con encabezados de actualización WebSocket.
- Echo responde del lado del cliente tomando el control de la conexión y solicita la actualización al servidor de destino configurado.
- El servidor de destino no atiende WebSocket en esa ruta, o lo rechaza, y contesta con una respuesta HTTP normal, por ejemplo 200 o 404, manteniendo la conexión activa.
- El bucle de copia sin procesar sigue funcionando, por lo que el atacante dispone ahora de un canal persistente al servidor de destino que Echo ya no inspecciona.
- El atacante escribe solicitudes HTTP normales en ese canal. Cada una se reenvía byte por byte al servidor de destino, y cada respuesta vuelve directamente.
- Ahora es accesible cualquier ruta o recurso que el servidor de destino ofrezca sin su propio control de autorización, incluso si las rutas de Echo habrían exigido autenticación para una solicitud equivalente.
Todas las condiciones de esa cadena importan: una ruta de proxy accesible, un servidor de destino que rechace sin cerrar y recursos de ese servidor que confíen en los controles de entrada del proxy.
Flujo del ataque
WebSocket a una ruta del proxy"] --> B["Echo elige proxyRaw y toma
el control de la conexión del cliente"] B --> C["Se escribe la solicitud en el destino,
sin leer nunca su respuesta"] C --> D["El destino rechaza con HTTP normal
y mantiene activa la conexión"] D --> E["El túnel sigue copiando,
sin comprobar la actualización"] E --> F["El atacante envía HTTP normal
por la misma conexión"] F --> G["Reenvío literal al destino,
eludiendo enrutador y middleware de Echo"] G --> H["Se entrega el recurso desprotegido,
se omite la autenticación de la ruta"]
¿Qué puede hacer un atacante?
El atacante accede a recursos del servidor de destino configurado que la capa de rutas de Echo habría protegido, con los privilegios de un cliente no autenticado. El impacto depende de lo que esos recursos expongan sin controles independientes: endpoints internos, servicios sin autenticación o paneles de administración que se suponían protegidos por el middleware de rutas del proxy. Los límites, según el aviso:
- No permite actuar como proxy hacia hosts arbitrarios. El túnel solo llega al servidor de destino configurado en el proxy, por lo que no es un proxy abierto.
- La autenticación propia del servidor de destino sigue aplicándose allí donde exista.
- Se necesita una ruta de proxy accesible y que el servidor de destino rechace la actualización sin cerrar la conexión.
- No se requiere autenticación, interacción del usuario ni una posición privilegiada, aparte del acceso de red a la ruta.
Dados esos límites, un resumen razonable es que la exposición real corresponde a los despliegues que aplican autenticación en Echo y confían en que el servidor de destino situado detrás sea inaccesible o no necesite autenticación. Sobre eso discrepan las dos calificaciones de severidad.
¿Por qué funciona la corrección?
El parche elimina por completo proxyRaw y envía todas las solicitudes, sean WebSocket o no, a través del proxy inverso de Go. Del commit de corrección de v4:
- // Proxy
- switch {
- case c.IsWebSocket():
- proxyRaw(tgt, c, config).ServeHTTP(res, req)
- default: // even SSE requests
- proxyHTTP(tgt, c, config).ServeHTTP(res, req)
- }
+ // ReverseProxy validates upgrades and closes both sides when a tunnel ends.
+ proxyHTTP(tgt, c, config).ServeHTTP(res, req)
Ahora proxyHTTP normaliza los esquemas de destino ws y wss a http y https y delega en httputil.NewSingleHostReverseProxy, que lee la respuesta del servidor de destino antes de continuar: solo se abre un túnel tras una respuesta válida 101 Switching Protocols, y una actualización rechazada se retransmite como la respuesta HTTP normal que es. Como indican las notas de la versión, las actualizaciones rechazadas ya no dejan un túnel sin procesar que eluda el enrutamiento y el middleware de rutas de Echo.
La corrección resuelve por completo este problema a nivel de middleware: ninguna ruta de Proxy entra ya en un túnel sin una actualización aceptada. El parche también cierra ambos extremos cuando cualquiera se desconecta, lo que corresponde al aviso complementario GHSA-9969-6676-49h5. La corrección no añade autenticación al servidor de destino; los recursos que antes carecían de controles independientes siguen igual de abiertos al tráfico autenticado y correctamente enrutado.
¿Cómo compruebo si he sufrido una intrusión?
No se han publicado indicadores de compromiso para este problema y Echo no enumera ninguno. El patrón de solicitudes que un atacante dejaría en los registros es característico, por lo que sus propios registros pueden aportar la respuesta:
- Conexiones a rutas del proxy con encabezados de actualización WebSocket,
Connection: UpgradeyUpgrade: websocket, que siguieron transportando tráfico HTTP tras una respuesta del servidor de destino distinta de 101. - Varias solicitudes HTTP normales registradas en el servidor de destino desde una única conexión de larga duración, sin que el proxy frontal haya registrado las correspondientes solicitudes enrutadas para ese mismo tráfico.
- Registros de acceso del servidor de destino que muestren solicitudes a recursos cuyo acceso debía controlar la capa de rutas de Echo.
Si los registros del servidor de destino incluyen las rutas de los recursos y los del proxy incluyen las rutas enrutadas, una discrepancia entre ambos para una conexión de cliente es la señal que debe investigarse.
Cronología
- 2026-10-22: Echo publica v4.16.1 y v5.4.1 con la corrección, y el responsable vishr publica el aviso GHSA-cxf3-9h37-7rr8, calificado como moderado y con reconocimiento a @Duodum.
- 2026-10-22: Las notas de v4.16.1 y v5.4.1 describen la nueva validación y las correcciones de seguridad complementarias.
- 2026-10-23: GitHub Advisory Database publica el aviso revisado como crítico, CVSS v4.0 9.1, con CWE-444 y CWE-863. Echo publica v4.16.2 con medidas adicionales de bastionado en la rama v4.
- 2026-10-24: Este artículo.
Preguntas frecuentes
¿Por qué discrepan las calificaciones de severidad?
La revisión de GitHub Advisory Database le asigna CVSS v4.0 9.1, crítico, y señala que existen requisitos de ataque, mientras que la página del aviso de Echo lo etiqueta como moderado sin publicar una puntuación. La discrepancia responde a las condiciones previas: el ataque necesita una ruta de proxy, un servidor de destino que rechace sin cerrar y recursos sin controles propios. Cuando se cumplen, la puntuación de la base de avisos considera completamente superado el límite de seguridad a nivel de ruta, lo que explica la urgencia de la corrección.
¿Puede convertir mi servidor en un proxy abierto?
No. El túnel solo se conecta al servidor de destino al que se configuró el middleware Proxy para reenviar solicitudes, y el aviso especifica que el problema no permite actuar como proxy hacia hosts arbitrarios. La exposición afecta a los recursos de su propio servidor de destino, no a destinos de terceros.
¿Elude la autenticación propia del servidor de destino?
No. Los mecanismos de autenticación del servidor de destino funcionan exactamente como antes. Se eluden los controles que residen únicamente en las rutas y el middleware de Echo; por eso, la medida provisional del aviso consiste en implementar autorización en el propio servidor de destino.
Mi servicio no utiliza el middleware Proxy de Echo. ¿Estoy afectado?
No. El error se encuentra en la ruta WebSocket sin procesar del middleware Proxy. Las aplicaciones que utilizan Echo para enrutamiento, archivos estáticos o sus propios manejadores y no montan ningún proxy no ejecutan esta ruta de código.
¿Qué otras correcciones incluyen v4.16.1 y v5.4.1?
Ambas versiones incluyen tres avisos complementarios calificados como altos en la base de datos: GHSA-9969-6676-49h5, conexiones del proxy WebSocket que permanecen abiertas tras desconectarse el cliente; GHSA-h7wr-284f-5qvc, expansión gzip sin límite en el middleware Decompress de v4; y GHSA-f48p-c9v4-h7xv, capturas BodyDump sin límite en v4. Si actualiza para corregir WebSocket, también resuelve esos problemas.
Escanee sus servicios Go e imágenes de contenedor con Ostorlab para identificar las versiones del módulo Echo que contienen y señalar los despliegues que siguen en v4.16.0 o v5.4.0 o versiones anteriores.
Referencias
- Aviso de Echo GHSA-cxf3-9h37-7rr8, calificado como moderado por el proveedor, publicado el 22 de octubre de 2026, con reconocimiento a @Duodum: https://github.com/labstack/echo/security/advisories/GHSA-cxf3-9h37-7rr8 (consultado el 24 de octubre de 2026)
- Revisión de GitHub Advisory Database, crítico, CVSS v4.0 9.1, CWE-444 y CWE-863: https://github.com/advisories/GHSA-cxf3-9h37-7rr8 (consultado el 24 de octubre de 2026)
- Commit de corrección en la rama v4, 3fb0ba7e: https://github.com/labstack/echo/commit/3fb0ba7e17645bb65611e2a08875d0a2f65c421f (consultado el 24 de octubre de 2026)
- Commit de corrección en la rama v5, 1855061e: https://github.com/labstack/echo/commit/1855061e572ae9dab727c811d8382f266bfbaaec (consultado el 24 de octubre de 2026)
- Notas de v4.16.1, publicada el 22 de octubre de 2026, con el requisito de Go 1.26 y las correcciones complementarias: https://github.com/labstack/echo/releases/tag/v4.16.1 (consultado el 24 de octubre de 2026)
- Notas de v5.4.1, publicada el 22 de octubre de 2026: https://github.com/labstack/echo/releases/tag/v5.4.1 (consultado el 24 de octubre de 2026)
- Notas de v4.16.2, publicada el 23 de octubre de 2026: https://github.com/labstack/echo/releases/tag/v4.16.2 (consultado el 24 de octubre de 2026)
- Código vulnerable de proxy.go en v4.16.0: https://raw.githubusercontent.com/labstack/echo/v4.16.0/middleware/proxy.go (consultado el 24 de octubre de 2026)
- Recuento de importaciones de echo/v4 en pkg.go.dev, 32.160 paquetes: https://pkg.go.dev/github.com/labstack/echo/v4 (consultado el 24 de octubre de 2026)
- Aviso complementario GHSA-9969-6676-49h5: https://github.com/advisories/GHSA-9969-6676-49h5 (consultado el 24 de octubre de 2026)
- Aviso complementario GHSA-h7wr-284f-5qvc: https://github.com/advisories/GHSA-h7wr-284f-5qvc (consultado el 24 de octubre de 2026)
- Aviso complementario GHSA-f48p-c9v4-h7xv: https://github.com/advisories/GHSA-f48p-c9v4-h7xv (consultado el 24 de octubre de 2026)