Resumen
ssrf_filter es una librería de Ruby pensada para hacer peticiones HTTP a URLs proporcionadas por terceros sin caer en SSRF. Cuando la respuesta es una redirección, la librería la sigue, pero lo hace reconstruyendo la nueva petición a partir de las opciones de la petición original: cabeceras, cuerpo y request_proc. No distinguía entre una redirección al mismo host y una a un host distinto.
La consecuencia es que, si una aplicación llamaba a SsrfFilter.get(...) con una cabecera Authorization destinada a un servidor concreto, y ese servidor respondía con un 302 hacia otro dominio, el token viajaba también a ese otro dominio. Quien controle el destino de la redirección recibe la credencial.
El código afectado está en lib/ssrf_filter/ssrf_filter.rb, en el bucle que procesa las redirecciones.
Pasos de reproducción
El investigador montó una prueba local con tres servidores:
redirector.test: responde con un 302 haciacollector.test.collector.test: guarda la cabeceraAuthorizationque le llega.api.test: expone/privatey solo devuelve datos si recibe el token bearer correcto.
- Clonar el repositorio y entrar en él:
``bash git clone https://github.com/arkadiyt/ssrf_filter cd ssrf_filter ``
- Ejecutar la prueba de concepto adjunta al reporte:
``bash ruby artifacts/ssrf_filter_redirect_leak_2026-04-01/01_bearer_token_replay.rb ``
- El script levanta los tres servidores y llama a
SsrfFilter.get(...)contraredirector.testcon una cabeceraAuthorization. La librería sigue el 302 y entrega esa misma cabecera acollector.test.
- Con el token capturado en
collector.test, el script hace una petición aapi.test/private, que responde con los datos protegidos.
Salida esperada:
[:fetch_response, "200", "stolen"]
[:stolen_token, "Bearer service-token-123"]
[:replay_response, "200", "private-data"]
Para poder ejecutarlo todo en una sola máquina, la prueba permite temporalmente las direcciones de loopback. Ese ajuste es solo del laboratorio: el fallo es el reenvío de credenciales al cambiar de host, no el acceso a loopback.
Impacto
Cualquier aplicación que use ssrf_filter para pedir recursos con credenciales (por ejemplo, un token de servicio en Authorization) puede acabar enviándolas a un tercero si la URL inicial redirige a un host que controla el atacante. La prueba demuestra que no se trata solo de que la cabecera quede expuesta: el token robado se pudo reutilizar contra otra API protegida y devolvió datos privados, es decir, robo de credenciales seguido de acceso no autorizado.
El reporte figura como resuelto; no detalla cómo se corrigió ni si hubo recompensa.
Qué aprender de este caso
- En cualquier cliente HTTP o envoltorio que siga redirecciones a mano, revisa qué opciones se copian de la petición original a la siguiente: si se reutiliza el mismo hash de cabeceras sin comparar host (y esquema y puerto) de origen y destino, hay fuga.
- Al cambiar de origen en una redirección, elimina como mínimo
Authorization,CookieyProxy-Authorization, y plantéate no reenviar el cuerpo. - Una librería "anti-SSRF" protege contra destinos internos, no contra destinos externos maliciosos: si tu aplicación añade credenciales a peticiones hacia URLs en las que influye un usuario, desactiva el seguimiento de redirecciones o valida cada salto.
- Al auditar integraciones (webhooks, importadores de URL, previsualizaciones), prueba a que el primer servidor responda con un 302 hacia un colector propio y mira qué cabeceras llegan.