Neutron, notre moteur d’IA, a obtenu un score de 97,1 % sur le benchmark CyberGym de l’UC Berkeley. En savoir plus

Analyse approfondie

Analyse approfondie

Contournement de l’authentification du proxy WebSocket d’Echo (GHSA-cxf3-9h37-7rr8)

Les passages à WebSocket refusés via le middleware Proxy d’Echo laissent un tunnel brut ouvert vers le serveur en amont. Les requêtes HTTP suivantes sur cette connexion évitent le routeur et les middlewares de route d’Echo, contournant ainsi l’authentification imposée uniquement sur ses routes. La GitHub Advisory Database classe la faille comme critique, CVSS v4.0 9.1, tandis qu’Echo la classe comme modérée. Corrigé dans v4.16.1 et v5.4.1, publiés le 22 octobre 2026. Aucune preuve de concept publique ni exploitation réelle n’est connue.

En bref

  • Lorsqu’un client demandait un passage à WebSocket sur une route gérée par le middleware Proxy d’Echo, les anciennes versions prenaient le contrôle de la connexion cliente et ouvraient directement une connexion au serveur en amont, en copiant les octets dans les deux sens sans jamais lire sa réponse. Si ce serveur refusait le changement de protocole par une réponse HTTP ordinaire tout en gardant la connexion ouverte, le tunnel restait actif.
  • Toute requête HTTP supplémentaire envoyée par l’attaquant sur cette même connexion était transmise directement au serveur en amont. Le routeur d’Echo et les middlewares de route, où la plupart des applications imposent l’authentification et l’autorisation, ne la voyaient donc jamais.
  • L’examen de la GitHub Advisory Database classe le problème comme critique, CVSS v4.0 9.1 ; les mainteneurs d’Echo classent leur propre bulletin comme modéré. CWE-444 et CWE-863 sont enregistrés. La faille ne figure pas dans le catalogue KEV, aucun exploit public n’existe et aucune exploitation réelle n’est connue au 24 octobre 2026.
  • Mettez à jour vers v4.16.1 ou ultérieure sur la branche v4, ou v5.4.1 ou ultérieure sur v5. En attendant, rejetez les demandes de passage à WebSocket avant qu’elles n’atteignent les routes du proxy, ou imposez une autorisation indépendante sur le serveur en amont.

Suis-je concerné ?

Vous êtes concerné si toutes ces conditions sont réunies :

  • Votre application ou passerelle d’API utilise Echo, module github.com/labstack/echo/v4 en version 4.16.0 ou antérieure, ou github.com/labstack/echo/v5 en version 5.4.0 ou antérieure.
  • Une route ou un groupe utilise le middleware Proxy intégré d’Echo (middleware.Proxy, ProxyWithConfig ou les fonctions d’équilibrage), de sorte qu’Echo transmet les requêtes à un serveur en amont.
  • Un client peut atteindre cette route proxifiée et y demander un passage à WebSocket.
  • Les contrôles de sécurité des ressources du serveur en amont résident dans les routes ou middlewares d’Echo plutôt que sur ce serveur lui-même.

Vous n’êtes pas concerné si vous ne montez jamais le middleware Proxy : le routage Echo classique, les middlewares d’authentification, la distribution de fichiers statiques et le reste sont hors du périmètre de ce bug. Le contournement ne permet pas non plus d’atteindre un hôte autre que le serveur en amont configuré dans le proxy, ni de contourner l’authentification propre à ce serveur. pkg.go.dev recense 32 160 packages qui importent github.com/labstack/echo/v4 (vérification le 24 octobre 2026), et seul le sous-ensemble qui monte le middleware Proxy est exposé.

Branche Versions affectées Version corrigée
echo/v4 >= 4.0.0, < 4.16.1 4.16.1
echo/v5 >= 5.0.0, < 5.4.1 5.4.1

Le bulletin mentionne des reproductions à l’exécution confirmant les versions v4.15.0, v4.16.0, v5.0.0 et v5.4.0, et précise que l’historique du code montre l’absence de validation depuis v4.0.0.

Vérifiez vos modules et leurs versions :

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 signale la plage affectée du module au titre de ce bulletin lorsqu’elle figure dans votre graphe de build.

Comment corriger le problème ?

Mettez le module à jour :

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

Notez le prérequis de la version v4.16.1 : les dépendances golang.org/x/ corrigées nécessitent Go 1.26 ou ultérieur. Votre chaîne de compilation peut donc aussi nécessiter une mise à jour. Les correctifs ultérieurs, comme v4.16.2 publié le 23 octobre 2026, contiennent la même correction et des améliorations complémentaires. Choisir le dernier correctif de votre branche convient donc également.

Si vous ne pouvez pas effectuer immédiatement la mise à jour, le bulletin propose deux solutions de contournement et précise une mesure qui n’en est pas une :

  • Rejetez les demandes de passage à WebSocket avant qu’elles n’atteignent les routes affectées du proxy. Un petit middleware placé devant le proxy et répondant à ces tentatives par une simple erreur ferme le point d’entrée.
  • Imposez une autorisation indépendante sur chaque ressource du serveur en amont, afin que les requêtes qui contournent la couche de routage d’Echo rencontrent tout de même de véritables contrôles.
  • Renvoyer simplement une réponse autre que 101 depuis le serveur en amont ne suffit pas, car c’est précisément ce refus qui laisse le tunnel vulnérable ouvert.

Les limites sont directes : la première solution désactive entièrement le proxy WebSocket ; la seconde ne protège que les ressources dotées de leurs propres contrôles, ce que l’application doit vérifier ressource par ressource.

Quelle est la cause racine ?

Le middleware Proxy d’Echo choisissait un tunnel d’octets brut pour les requêtes WebSocket avant de vérifier si le serveur en amont avait accepté le changement de protocole. Le tunnel continuait donc à fonctionner après son refus.

La sélection du traitement, dans middleware/proxy.go à la version v4.16.0, ligne 391 :

// Proxy
switch {
case c.IsWebSocket():
    proxyRaw(tgt, c, config).ServeHTTP(res, req)
default: // even SSE requests
    proxyHTTP(tgt, c, config).ServeHTTP(res, req)
}

Le problème est dans proxyRaw (ligne 134). Cette fonction prend le contrôle de la connexion cliente, se connecte au serveur en amont et copie les octets dans les deux sens :

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)

Remarquez ce qui manque : r.Write(out) envoie la demande de changement de protocole, puis deux boucles io.Copy transfèrent indéfiniment les octets. Mais rien ne lit la réponse HTTP du serveur en amont à cette demande, et rien ne conditionne l’ouverture du tunnel à une réponse 101 Switching Protocols. À l’inverse, proxyHTTP, la branche non-WebSocket, délègue à httputil.NewSingleHostReverseProxy de Go, un composant qui valide bien les réponses du serveur en amont.

Les conséquences en découlent directement. Dès que la connexion cliente est reprise, Echo cesse d’y traiter les requêtes. Si le serveur en amont répond à la tentative de changement de protocole par une réponse HTTP ordinaire et, condition essentielle, garde la connexion TCP ouverte avec HTTP keep-alive, la boucle de copie brute continue à transmettre les données. Le client reçoit les octets du refus, puis peut envoyer une autre requête HTTP ordinaire sur la même connexion. cp(out, in) la transmet à l’identique au serveur en amont, et sa réponse revient par le même chemin. Le routeur d’Echo, les middlewares de route, les limites de débit et l’authentification au niveau des routes sont tous contournés pour ces requêtes, car, du point de vue d’Echo, la connexion a quitté le traitement HTTP au moment de sa reprise.

Comment la faille est-elle exploitée ?

Aucune preuve de concept publique n’existe. Le bulletin, publié par le mainteneur vishr et créditant le chercheur @Duodum, décrit le mécanisme et indique que les mainteneurs ont reproduit le flux à l’exécution sur v4.15.0, v4.16.0, v5.0.0 et v5.4.0. Voici le chemin d’attaque décrit :

  1. L’attaquant ouvre une connexion vers une route Echo utilisant le middleware Proxy et envoie une requête HTTP avec des en-têtes de passage à WebSocket.
  2. Echo prend le contrôle de la connexion côté client et demande le changement de protocole au serveur en amont configuré.
  3. Le serveur en amont n’accepte pas WebSocket sur ce chemin, ou refuse la demande, et répond par une réponse HTTP ordinaire, par exemple 200 ou 404, sur une connexion qu’il garde ouverte.
  4. La boucle de copie brute continue : l’attaquant dispose désormais d’un canal persistant vers le serveur en amont, qu’Echo n’inspecte plus.
  5. L’attaquant écrit des requêtes HTTP ordinaires dans ce canal. Chacune est transmise octet pour octet au serveur en amont, et chaque réponse revient directement.
  6. Tout chemin ou toute ressource servis en amont sans contrôle d’autorisation propre deviennent accessibles, même si les routes d’Echo auraient exigé une authentification pour la requête équivalente.

Chaque condition de cette chaîne compte : une route de proxy accessible, un serveur en amont qui refuse sans fermer la connexion et des ressources qui font confiance aux contrôles d’entrée du proxy.

Déroulement de l’attaque

flowchart LR A["L’attaquant demande un passage
à WebSocket sur la route du proxy"] --> B["Echo choisit proxyRaw et
reprend la connexion cliente"] B --> C["Requête brute envoyée en amont,
réponse jamais lue"] C --> D["Le serveur refuse en HTTP ordinaire
et garde la connexion ouverte"] D --> E["Le tunnel poursuit la copie,
sans validation du changement"] E --> F["L’attaquant envoie du HTTP ordinaire
sur la même connexion"] F --> G["Transmission à l’identique en amont,
sans routeur ni middleware Echo"] G --> H["Ressource en amont non protégée servie,
authentification de route contournée"]

Que peut faire un attaquant ?

L’attaquant atteint des ressources du serveur en amont configuré que la couche de routage d’Echo aurait protégées, avec les privilèges d’un client non authentifié. L’impact dépend de ce que ces ressources exposent sans contrôles indépendants : endpoints internes, services non authentifiés, panneaux d’administration supposés protégés par le middleware de route du proxy. Voici les limites précisées dans le bulletin :

  • Aucun proxy vers un hôte arbitraire. Le tunnel mène uniquement au serveur en amont configuré dans le proxy : il ne s’agit donc pas d’un proxy ouvert.
  • L’authentification propre au serveur en amont continue de s’appliquer là où elle existe.
  • Une route de proxy accessible est nécessaire, et le serveur en amont doit refuser le changement de protocole sans fermer la connexion.
  • Aucune authentification, interaction utilisateur ou position privilégiée n’est requise au-delà de l’accès réseau à la route.

Compte tenu de ces limites, les déploiements réellement exposés sont ceux qui imposent l’authentification dans Echo et comptent sur le fait que le serveur en amont soit inaccessible ou non authentifié derrière lui. C’est sur cette exposition que les deux évaluations de sévérité divergent.

Pourquoi le correctif fonctionne-t-il ?

Le correctif supprime entièrement proxyRaw et fait passer toutes les requêtes, WebSocket ou non, par le reverse proxy de Go. Extrait du commit de correction 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)

proxyHTTP normalise désormais les schémas cibles ws et wss en http et https, puis délègue à httputil.NewSingleHostReverseProxy, qui lit la réponse du serveur en amont avant de poursuivre : le tunnel n’est ouvert qu’après une réponse 101 Switching Protocols valide, et un refus est relayé comme la réponse HTTP ordinaire qu’il est. Comme l’expliquent les notes de version, les changements de protocole refusés ne laissent plus de tunnel brut permettant de contourner le routage et les middlewares de route d’Echo.

Le correctif résout entièrement ce problème au niveau du middleware : aucun chemin de Proxy n’ouvre plus de tunnel sans acceptation du changement de protocole. Il ferme aussi les deux côtés lorsque l’un se déconnecte, ce qui correspond au bulletin associé GHSA-9969-6676-49h5. En revanche, le correctif n’ajoute pas d’authentification à votre serveur en amont : les ressources qui n’avaient pas de contrôles indépendants restent tout aussi accessibles qu’auparavant au trafic correctement routé et authentifié.

Comment vérifier si j’ai été compromis ?

Aucun indicateur de compromission n’est publié pour ce problème, et Echo n’en recense aucun. Le motif de requêtes qu’un attaquant laisserait dans les journaux est distinctif ; vos propres journaux peuvent donc apporter une réponse :

  • Des connexions aux routes proxifiées avec les en-têtes de passage à WebSocket, Connection: Upgrade et Upgrade: websocket, qui continuent à transporter du trafic HTTP après une réponse du serveur en amont autre que 101.
  • Plusieurs requêtes HTTP ordinaires enregistrées en amont depuis une même connexion de longue durée, alors que le proxy frontal ne consigne aucune requête routée correspondante pour ce trafic.
  • Des traces d’accès en amont montrant des requêtes vers des ressources dont la couche de routage Echo était censée contrôler l’accès.

Si les journaux du serveur en amont contiennent les chemins des ressources et ceux du proxy les chemins routés, une divergence entre les deux pour une même connexion cliente constitue le signal à examiner.

Chronologie

  • 2026-10-22 : Echo publie v4.16.1 et v5.4.1 avec le correctif, et le mainteneur vishr publie le bulletin GHSA-cxf3-9h37-7rr8, classé modéré, en créditant @Duodum.
  • 2026-10-22 : les notes de version de v4.16.1 et v5.4.1 décrivent la nouvelle validation et les correctifs de sécurité associés.
  • 2026-10-23 : la GitHub Advisory Database publie le bulletin en cours d’examen comme critique, CVSS v4.0 9.1, avec CWE-444 et CWE-863. Echo publie v4.16.2 avec un durcissement complémentaire sur la branche v4.
  • 2026-10-24 : publication de cet article.

FAQ

Pourquoi les évaluations de sévérité divergent-elles ?

L’examen de la GitHub Advisory Database attribue un score CVSS v4.0 de 9.1, critique, avec des conditions d’attaque signalées comme présentes, tandis que le bulletin d’Echo lui-même indique une sévérité modérée sans score publié. La divergence porte sur les prérequis : l’attaque nécessite une route de proxy, un serveur en amont qui refuse sans fermer la connexion et des ressources dépourvues de contrôles propres. Lorsque ces conditions sont réunies, l’évaluation de la base de bulletins considère la frontière de sécurité au niveau des routes comme entièrement contournée, ce qui explique l’urgence du correctif.

Cette faille peut-elle transformer mon serveur en proxy ouvert ?

Non. Le tunnel ne se connecte qu’au serveur en amont vers lequel le middleware Proxy est configuré pour transmettre les requêtes. Le bulletin précise que le problème ne permet pas d’utiliser le proxy vers des hôtes arbitraires. L’exposition concerne les ressources de votre propre serveur en amont, pas des destinations tierces.

Contourne-t-elle l’authentification propre au serveur en amont ?

Non. Les mécanismes d’authentification du serveur en amont fonctionnent exactement comme auparavant. Ce qui est contourné, ce sont les contrôles présents uniquement dans les routes et middlewares d’Echo. C’est pourquoi la solution de contournement du bulletin consiste à placer l’autorisation sur le serveur en amont lui-même.

Mon service n’utilise pas le middleware Proxy d’Echo. Suis-je concerné ?

Non. Le bug réside dans le chemin WebSocket brut du middleware Proxy. Les applications qui utilisent Echo pour le routage, les fichiers statiques ou leurs propres gestionnaires, sans monter de proxy, n’empruntent pas ce chemin de code.

Quels autres correctifs accompagnent v4.16.1 et v5.4.1 ?

Les deux versions regroupent trois bulletins associés classés de sévérité élevée dans la base : GHSA-9969-6676-49h5, connexions du proxy WebSocket conservées après la déconnexion d’un client ; GHSA-h7wr-284f-5qvc, expansion gzip non bornée dans le middleware Decompress de v4 ; et GHSA-f48p-c9v4-h7xv, captures BodyDump non bornées dans v4. Si vous effectuez la mise à jour pour le correctif WebSocket, vous corrigez également ces problèmes.

Scannez vos services Go et vos images de conteneurs avec Ostorlab pour identifier les versions du module Echo qu’ils embarquent et repérer les déploiements encore en v4.16.0, v5.4.0 ou antérieures.

Références

  • Bulletin Echo GHSA-cxf3-9h37-7rr8, classé modéré par l’éditeur, publié le 22 octobre 2026, avec attribution à @Duodum : https://github.com/labstack/echo/security/advisories/GHSA-cxf3-9h37-7rr8 (consulté le 24 octobre 2026)
  • Examen de la GitHub Advisory Database, critique, CVSS v4.0 9.1, CWE-444 et CWE-863 : https://github.com/advisories/GHSA-cxf3-9h37-7rr8 (consulté le 24 octobre 2026)
  • Commit du correctif sur la branche v4, 3fb0ba7e : https://github.com/labstack/echo/commit/3fb0ba7e17645bb65611e2a08875d0a2f65c421f (consulté le 24 octobre 2026)
  • Commit du correctif sur la branche v5, 1855061e : https://github.com/labstack/echo/commit/1855061e572ae9dab727c811d8382f266bfbaaec (consulté le 24 octobre 2026)
  • Notes de version v4.16.1, publiées le 22 octobre 2026, incluant le prérequis Go 1.26 et les correctifs associés : https://github.com/labstack/echo/releases/tag/v4.16.1 (consultées le 24 octobre 2026)
  • Notes de version v5.4.1, publiées le 22 octobre 2026 : https://github.com/labstack/echo/releases/tag/v5.4.1 (consultées le 24 octobre 2026)
  • Notes de version v4.16.2, publiées le 23 octobre 2026 : https://github.com/labstack/echo/releases/tag/v4.16.2 (consultées le 24 octobre 2026)
  • Code vulnérable de proxy.go à la version v4.16.0 : https://raw.githubusercontent.com/labstack/echo/v4.16.0/middleware/proxy.go (consulté le 24 octobre 2026)
  • Nombre de packages important echo/v4 sur pkg.go.dev, 32 160 packages : https://pkg.go.dev/github.com/labstack/echo/v4 (consulté le 24 octobre 2026)
  • Bulletin associé GHSA-9969-6676-49h5 : https://github.com/advisories/GHSA-9969-6676-49h5 (consulté le 24 octobre 2026)
  • Bulletin associé GHSA-h7wr-284f-5qvc : https://github.com/advisories/GHSA-h7wr-284f-5qvc (consulté le 24 octobre 2026)
  • Bulletin associé GHSA-f48p-c9v4-h7xv : https://github.com/advisories/GHSA-f48p-c9v4-h7xv (consulté le 24 octobre 2026)