Reports
ALTA[XSS]#3830771

XSS reflejado sin autenticación en un script CGI heredado en Perl de Essity

Un formulario de registro en Perl, olvidado en /cgi-bin/ de un dominio de Essity, devolvía un parámetro tal cual en el HTML. Bastaba un enlace para ejecutar JavaScript en ese origen, sin necesidad de sesión.

Resumen
Resumen en castellano de un reporte público, no una traducción literal. El código y los comandos se mantienen como en el original.

Resumen

En un dominio de Essity seguía publicado un script CGI escrito en Perl, una herramienta interna antigua (los metadatos de la página la atribuyen a SCA/Essity). El script tiene una acción Register que recibe varios datos de contacto y los vuelve a pintar en la respuesta. Uno de esos parámetros (su nombre está tapado en la divulgación) se insertaba en el HTML sin ningún tipo de codificación de salida, así que cualquier etiqueta que llegase en él se interpretaba como parte de la página.

El resultado es un XSS reflejado clásico: no hace falta estar autenticado y funciona tanto por GET como por POST. La ruta, el host y el nombre del parámetro aparecen ocultos (████████) en el reporte publicado.

El reporte se envió el 29 de junio de 2026 y se divulgó al día siguiente, ya resuelto, con severidad alta.

Pasos de reproducción

  1. Sin iniciar sesión, abrir esta URL, que mete un <script> codificado en URL dentro del parámetro vulnerable:
https://████████/cgi-bin/████████.pl?action=Register&████████=%3Cscript%3Ealert(document.domain)%3C%2Fscript%3E&last=████████&████████=123
  1. Mirar el cuerpo de la respuesta. El payload aparece decodificado y sin escapar, junto al resto de datos del "registro":
<br>
<script>alert(document.domain)</script> ████████, Tel: 123
<br>
  1. Para confirmarlo fuera del navegador, el investigador usó curl con la cabecera de identificación de investigación de HackerOne:
curl -sk -H "X-HackerOne-Research: ████████" \
"https://████████/cgi-bin/████████.pl?action=Register&████████=%3Cscript%3Ealert(document.domain)%3C%2Fscript%3E&last=████████&████████=123"
  1. Enviar los mismos parámetros por POST da el mismo resultado: el fallo no depende del método.

Según el reporte, el parámetro last y otro más (también oculto en la divulgación) se reflejan igualmente en la respuesta, pero el investigador solo confirmó que aparecían, sin llegar a explotarlos.

Impacto

Quien abriese un enlace preparado ejecutaría JavaScript del atacante en el origen del dominio de Essity, sin necesidad de autenticación. A partir de ahí, el reporte señala:

  • Robo de sesión de los usuarios de ese origen.
  • Phishing de credenciales servido desde un dominio de Essity, lo que lo hace mucho más creíble.
  • Inyección de contenido o desfiguración de la página.

Además, el código fuente de la página filtraba metadatos de infraestructura interna, en concreto el nombre de un host interno.

Remediación

El reporte figura como resuelto, pero no detalla qué se hizo (si se retiró el script o se añadió codificación de salida). La corrección natural es escapar en HTML cada valor antes de escribirlo en la respuesta o, si la herramienta ya no se usa, retirarla del servidor.

Qué aprender de este caso

  • Los directorios /cgi-bin/ de dominios corporativos antiguos merecen un repaso: los scripts .pl que nadie mantiene suelen imprimir los parámetros con print directamente, sin ninguna plantilla que escape por defecto.
  • Las acciones que "confirman" lo que acaba de enviar el usuario (registro, resumen de un formulario, "Gracias, X, te llamaremos al Y") son el sitio típico donde buscar un reflejo: prueba cada campo, no solo el primero, y con GET y POST.
  • En Perl, cualquier valor que acabe en HTML debe pasar por una función de escape como escapeHTML de CGI.pm o encode_entities de HTML::Entities antes del print; sin eso, el script es vulnerable por diseño.
  • Revisa también la etiqueta <meta name="generator"> y los comentarios del HTML de estas herramientas: en este caso dejaban ver un host interno, una pista útil para un atacante.