Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2026-66418-OpenClaw-Dashboard-v3.0.0-Stored-XSS-via-Failed-Login-Username-Field — Уведомление о безопасности: неаутентифицированная хранимая межсайтовая XSS-уязвимость, приводящая к захвату учётной записи администратора (openclaw-dashboard) | Kitploit
Инструменты/GitHubGitHub/theopaid/cve-2026-66418-openclaw-dashboard-v3.0.0-stored-xss-via-failed-login-username-field
Анализ уязвимостейЭксплуатация веб-приложенийВеб-безопасностьОбучение и Образование
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

Уведомление о безопасности: неаутентифицированная хранимая межсайтовая XSS-уязвимость, приводящая к захвату учётной записи администратора (openclaw-dashboard)

Репозиторий

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться
18 дней назадЕщё не проверено

Бюллетень безопасности: неаутентифицированный сохранённый межсайтовый скриптинг (XSS), приводящий к захвату учётной записи администратора (openclaw-dashboard)

Title: OpenClaw Dashboard v3.0.0 — сохранённый XSS через поле имени пользователя при неудачном входе Назначенный идентификатор CVE: CVE-2026-66418

Целевой репозиторий: https://github.com/tugcantopaloglu/openclaw-dashboard

Краткое описание

Конечная точка входа записывает отправленное имя пользователя в журнал аудита без какой-либо проверки. Панель уведомлений позже читает эти записи журнала и вставляет их на страницу с помощью innerHTML без экранирования. Злоумышленник, который не может войти в систему, всё равно может отправить запрос на неудачный вход, указав в качестве имени пользователя полезную нагрузку-скрипт. При следующем открытии администратором колокольчика уведомлений эта полезная нагрузка выполняется в его браузере, в origin панели управления, и получает доступ к его токену сессии.

  • CWE-79: Некорректная нейтрализация входных данных при генерации веб-страницы (Cross-site Scripting)
  • CWE-117: Некорректная нейтрализация вывода для журналов
  • CVSS 4.0: 9.3 (Critical). Вектор: 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

Затронутые версии

Проблема появилась в v3.0.0, где был добавлен центр уведомлений, отображающий записи журнала аудита. Присутствует в v3.0.0 и во всех последующих коммитах вплоть до текущей ветки main (d6198d0) включительно. На момент написания не исправлена.

Модель угроз

Злоумышленник — удалённая сторона, которая может обратиться к HTTP-порту панели управления, но не имеет учётной записи и действительных учётных данных. Это соответствует тому, что страница входа доступна любому, кто может открыть панель управления. Единственное предусловие — уже существующая учётная запись администратора, что верно для любого развёртывания после первичной настройки.

Полезная нагрузка сохраняется, поэтому синхронизация по времени не требуется. Она выполняется, когда администратор открывает панель уведомлений — обычное действие, предлагаемое интерфейсом. После запуска она получает те же возможности, что и браузер администратора: может прочитать токен сессии и вызывать любые аутентифицированные конечные точки от имени жертвы.

Корневая причина

Шаг 1. Имя пользователя записывается в журнал как есть. Вход с именем пользователя, которое не совпадает с зарегистрированной учётной записью, попадает в эту ветку:

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 берётся напрямую из тела JSON-запроса. Нет ограничения длины, разрешённого набора символов или проверки типа. auditLog записывает его на диск в виде 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 экранирует кавычки и символы новой строки, поэтому полезная нагрузка остаётся на одной строке и корректно разбирается обратно. Он не экранирует <, > и /, поэтому HTML-разметка сохраняется без изменений.

Шаг 2. Журнал считывается обратно. Конечная точка уведомлений возвращает браузеру последние строки журнала:

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 }));

Шаг 3. Имя пользователя записывается в DOM без экранирования. Фронтенд формирует каждую строку уведомления через конкатенацию строк и присваивает её через 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 — строка злоумышленника. Она попадает в innerHTML без кодирования, поэтому браузер разбирает её как HTML.

Политика безопасности контента, заданная в server.js:298, включает script-src 'self' 'unsafe-inline', поэтому встроенные обработчики событий, такие как onerror, могут выполняться.

Доказательство концепции

  1. Убедитесь, что учётная запись администратора существует (любая стандартная установка). Злоумышленнику не нужны её учётные данные.

  2. В роли неаутентифицированного злоумышленника отправьте один неудачный вход, указав в качестве имени пользователя полезную нагрузку:

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

    Сервер отвечает 401 Invalid username or password и сохраняет полезную нагрузку.

  3. Администратор входит в систему обычным образом и нажимает на колокольчик уведомлений.

  4. Полезная нагрузка выполняется в сессии администратора. В этом примере она считывает токен сессии с помощью собственной функции страницы getStoredToken() и использует его для перезаписи файла инструкций агента AGENTS.md через POST /api/key-file. Любая аутентифицированная конечная точка может быть вызвана таким же образом.

Текст полезной нагрузки остаётся одной строкой журнала и возвращается байт-в-байт через /api/notifications, поэтому инъекцию и выполнение можно подтвердить по отдельности.

Воздействие

Выполнение кода в origin панели управления с правами администратора. Скрипт может прочитать токен сессии и отправлять любые аутентифицированные запросы, включая изменение файлов инструкций и навыков агента и изменение конфигурации OpenClaw. Поскольку злоумышленнику не нужна учётная запись, этот неаутентифицированный сетевой запрос превращается в контроль над сессией администратора.

Устранение

  • HTML-кодируйте каждое значение перед помещением в innerHTML или создавайте узлы с помощью textContent вместо конкатенации строк. Это касается полей имени пользователя, события и IP-адреса в уведомлениях.
  • Проверяйте username на сервере перед записью в журнал: ограничьте его длину и разрешите только ожидаемый набор символов.
  • Удалите 'unsafe-inline' из script-src. Если встроенные обработчики будут заблокированы, эта проблема снижается с выполнения кода до безвредной разметки.
Скачать инструмент