Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
Herramientas/GitHubGitHub/theopaid/cve-2026-66418-openclaw-dashboard-v3.0.0-stored-xss-via-failed-login-username-field
Análisis de VulnerabilidadesExplotación de Aplicaciones WebSeguridad WebAprendizaje y Educación
GitHubtheopaid/cve-2026-66418-openclaw-dashboard-v3.0.0-stored-xss-via-failed-login-username-field

CVE-2026-66418-OpenClaw-Dashboard-v3.0.0-Stored-XSS-via-Failed-Login-Username-Field

Aviso de seguridad: Cross-Site Scripting Almacenado No Autenticado que permite la toma de control de la cuenta de administrador (openclaw-dashboard)

Ver Repositorio

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir
hace 17 díasAún no revisado

Aviso de seguridad: Cross-Site Scripting almacenado no autenticado que conduce a la toma de control de la cuenta de administrador (openclaw-dashboard)

Título: OpenClaw Dashboard v3.0.0 XSS almacenado a través del campo de nombre de usuario en inicio de sesión fallido ID de CVE asignado: CVE-2026-66418

Repositorio objetivo: https://github.com/tugcantopaloglu/openclaw-dashboard

Resumen

El endpoint de inicio de sesión registra el nombre de usuario enviado en el registro de auditoría sin ninguna validación. El panel de notificaciones lee posteriormente esas entradas del registro y las escribe en la página con innerHTML y sin escape. Un atacante que no puede iniciar sesión puede enviar una solicitud de inicio de sesión fallida cuyo nombre de usuario sea una carga útil de script. La próxima vez que el administrador autenticado abra la campana de notificaciones, esa carga útil se ejecuta en su navegador, en el origen del dashboard, con acceso a su token de sesión.

  • CWE-79: Neutralización incorrecta de la entrada durante la generación de la página web (Cross-site Scripting)
  • CWE-117: Neutralización incorrecta de la salida en los registros
  • CVSS 4.0: 9.3 (Crítico). Vector: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:A/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N

Versiones afectadas

Introducido en v3.0.0, que añadió el centro de notificaciones que renderiza las entradas del registro de auditoría. Presente en v3.0.0 y en todos los commits posteriores hasta el main actual inclusive (d6198d0). Sin corregir en el momento de redactar este documento.

Modelo de amenaza

El atacante es una entidad remota que puede alcanzar el puerto HTTP del dashboard pero no tiene cuenta ni credenciales válidas. Esto coincide con que la pantalla de inicio de sesión sea accesible para cualquiera que pueda abrir el dashboard. La única condición previa es que ya exista una cuenta de administrador, algo cierto en cualquier despliegue posterior a la configuración inicial.

La carga útil se almacena, por lo que no se necesita coordinación de tiempos. Se ejecuta cuando el administrador abre el panel de notificaciones, una acción normal que ofrece la interfaz de usuario. Una vez que se ejecuta, tiene las mismas capacidades que el navegador del administrador: puede leer el token de sesión y llamar a cualquier endpoint autenticado en nombre de la víctima.

Causa raíz

Paso 1. El nombre de usuario se registra tal cual. Un inicio de sesión con un nombre de usuario que no coincide con la cuenta registrada llega a esta rama:

root@kitploit:~
// server.js:1577-1583
if (username !== creds.username) {
  recordFailedAuth(ip);
  auditLog('login_failed', ip, { username });
  res.writeHead(401, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({ error: 'Invalid username or password' }));
  return;
}

username proviene directamente del cuerpo de la solicitud JSON. No hay límite de longitud, lista blanca de caracteres ni comprobación de tipo. auditLog lo escribe en disco como una línea JSON:

root@kitploit:~
// server.js:278-282
function auditLog(event, ip, details = {}) {
  try {
    const timestamp = new Date().toISOString();
    const entry = JSON.stringify({ timestamp, event, ip, ...details }) + '\n';
    fs.appendFileSync(auditLogPath, entry, 'utf8');

JSON.stringify escapa las comillas y los saltos de línea, por lo que la carga útil permanece en una sola línea y se vuelve a analizar limpiamente. No escapa <, > ni /, por lo que el marcado HTML sobrevive intacto.

Paso 2. El registro se lee de vuelta. El endpoint de notificaciones devuelve al navegador las líneas recientes del registro:

root@kitploit:~
// server.js:2042-2051
if (req.url.startsWith('/api/notifications')) {
  if (!requireAuth(req, res)) return;
  const limit = parseInt(new URL(req.url, 'http://localhost').searchParams.get('limit') || '50');
  try {
    const raw = fs.readFileSync(auditLogPath, 'utf8').trim();
    const lines = raw.split('\n').filter(Boolean).slice(-Math.min(limit, 200));
    const events = lines.map(l => { try { return JSON.parse(l); } catch { return null; } }).filter(Boolean).reverse();
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ events }));

Paso 3. El nombre de usuario se escribe en el DOM sin escape. El frontend construye cada fila de notificación mediante concatenación de cadenas y la asigna con innerHTML:

root@kitploit:~
// index.html:5647-5653
body.innerHTML = data.events.map(e => {
  const icon = notifIcons[e.event] || '📋';
  const time = e.timestamp ? new Date(e.timestamp).toLocaleString() : '';
  const detail = e.username ? ' (' + e.username + ')' : '';
  const ip = e.ip ? ' from ' + e.ip : '';
  return '<div class="notif-item"><div class="notif-icon">' + icon + '</div><div class="notif-content"><div class="notif-event">' + (e.event||'').replace(/_/g, ' ') + detail + ip + '</div><div class="notif-time">' + time + '</div></div></div>';
}).join('');

e.username es la cadena del atacante. Llega a innerHTML sin codificación, por lo que el navegador la analiza como HTML.

La Content-Security-Policy definida en server.js:298 incluye script-src 'self' 'unsafe-inline', por lo que los manejadores de eventos en línea como onerror pueden ejecutarse.

Prueba de concepto

  1. Asegúrate de que existe una cuenta de administrador (cualquier instalación normal). El atacante no necesita sus credenciales.

  2. Como atacante no autenticado, envía un inicio de sesión fallido cuyo nombre de usuario sea la carga útil:

    root@kitploit:~
    curl -X POST http://TARGET:7000/api/auth/login \
      -H 'Content-Type: application/json' \
      -d '{"username":"","password":"x"}'
    

    El servidor responde 401 Invalid username or password y almacena la carga útil.

  3. El administrador inicia sesión normalmente y hace clic en la campana de notificaciones.

  4. La carga útil se ejecuta en la sesión del administrador. En este ejemplo, lee el token de sesión con la función getStoredToken() de la propia página y lo usa para sobrescribir el archivo de instrucciones del agente AGENTS.md mediante POST /api/key-file. Cualquier endpoint autenticado se puede llamar de la misma manera.

El texto de la carga útil permanece como una única línea del registro y regresa byte a byte a través de /api/notifications, por lo que la inyección y la ejecución pueden confirmarse por separado.

Impacto

Ejecución de código en el origen del dashboard como administrador. El script puede leer el token de sesión y realizar cualquier solicitud autenticada, incluida la edición de los archivos de instrucciones y habilidades del agente y el cambio de la configuración de OpenClaw. Debido a que el atacante no necesita una cuenta, esto convierte una solicitud de red no autenticada en el control de la sesión del administrador.

Remediación

  • Codifica en HTML cada valor antes de colocarlo en innerHTML, o construye los nodos con textContent en lugar de concatenación de cadenas. Los campos de nombre de usuario, evento e IP de las notificaciones necesitan esto.
  • Valida username en el servidor antes de registrarlo: limita su longitud y restringe el conjunto de caracteres esperado.
  • Elimina 'unsafe-inline' de script-src. Con los manejadores en línea bloqueados, este problema pasa de ejecución de código a marcado inofensivo.
Descargar herramienta