FlawOpen

flawopen.com/Teardowns/cve-2026-10032-a2ui-agent-button-xss

● CVE-2026-10032 · CVSS 9.3[1] · Критическая
Исследования · FlawOpen

CVE-2026-10032: XSS через кнопки A2UI, созданные агентом

В уязвимых версиях openUrl из Basic Catalog по умолчанию передавал URL агента в window.open без ограничения схемы. Для описанного в уведомлении воздействия на origin браузера пользователь должен был нажать Button; обновитесь до 0.10.2 или новее.[1]

Вектор CVSSCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N[1]
💡 Простыми словами (ELI5)

Представьте киоск, где помощник добавляет кнопку, а адрес записан на переданной им карточке. Киоск проверяет наличие адреса, но не ведёт ли он на обычную веб-страницу. Посетителю нужно нажать кнопку; без правила браузер может принять адрес за инструкцию самому киоску. Исправление разбирает адрес и принимает только HTTP- или HTTPS-направления.[1], [2]

Ключевые понятия и термины

A2UI
Протокол и проект с открытым кодом для интерфейсов агентов; уведомление относится к Basic Catalog в web_core.[1]
Базовый каталог
Встроенный набор функций A2UI; по уведомлению, включён по умолчанию.[1]
Действие-вызов функции
Декларативное действие UI с функцией и аргументами; Button мог вызвать openUrl с URL агента.[1], [2]
CWE-79
Классификация ненадлежащей нейтрализации ввода при создании веб-страницы; уведомление относит сюда инъекцию в браузере.[1], [4]

Связи со стандартами

  • Ссылка CWE для слабого места, описанного в этом руководстве: CWE-79

Анализ первопричины

Basic Catalog считал URL строкой для открытия, а не недоверенным навигационным вводом с политикой схем. API проверял тип, но код не ограничивал протокол перед window.open(args.url, '_blank'). Button.functionCall агента мог передать значение к sink. Пользователь должен был нажать кнопку; уведомление A2UI описывает выполнение скрипта в origin браузера приложения-жертвы. Исправление разбирает URL, разрешает только http: и https:, затем открывает нормализованный адрес с noopener,noreferrer. Оно исправляет этот путь, но не гарантирует безопасность любого интерфейса агента.[1], [2]

CVE-2026-10032: уязвимые версии и граница действия

Условие развёртыванияЧто подтверждает уведомлениеЗащитное действие
@a2ui/web_core 0.9.0, 0.9.1, 0.9.2, 0.10.0 или 0.10.1 с Basic Catalog по умолчанию.Уведомление указывает эти версии как уязвимые; Basic Catalog включён по умолчанию.Обновитесь до 0.10.2 или новее и проверьте версию приложения.
Вызов Button поступает из данных A2UI агента, и пользователь нажимает кнопку.Уведомление описывает переход к openUrl после щелчка и влияние на origin браузера; это не zero-click.Считайте аргументы недоверенными и проверяйте их в функции открытия URL.
Приложение использует React-, Lit- или Angular-рендерер A2UI.Уведомление включает интеграции; уязвимая граница — Basic Catalog в web_core.Проверьте пакет и обновите web_core.
Приложение работает на @a2ui/web_core 0.10.2 или новее.Разработчики называют 0.10.2 исправленной версией: разбор URL, HTTP/HTTPS и noopener,noreferrer.Сохраните тесты допустимых схем и проверьте свою замену openUrl.

Пошаговый сценарий атаки

Шаг 1

Агент задаёт действие Button

Данные A2UI могут задавать Button с вызовом функции и аргументами. Считайте действия агента недоверенными.[1]

Шаг 2

Basic Catalog разрешает openUrl

Basic Catalog предоставляет openUrl; схема требует строку, но код не ограничивал схему URL.[1]

Шаг 3

Пользователь нажимает Button

Этот путь требует щелчка пользователя. Не называйте его атакой без взаимодействия.[1], [2]

Шаг 4

Действие достигает window.open

До патча openUrl передавал строку в window.open без проверки протокола. Уведомление описывает выполнение в origin приложения-жертвы.[1]

Шаг 5

Исправленное действие ограничивает переход

Исправление разрешает URL, отклоняет протоколы кроме HTTP/HTTPS и использует noopener,noreferrer. Обновитесь до 0.10.2 или новее.[1], [2]

Исходный код: Уязвимый vs Защищённый вариант

Уязвимый фрагмент взят из реализации, указанной в уведомлении A2UI. PR #1707 разбирает адрес, допускает только HTTP/HTTPS и не позволяет открытой странице управлять исходной или получать referrer. Типы и импорты опущены; это не полная программа и не proof of concept.[1], [2]

Фрагмент исходного кода: basic_functions.ts — OpenUrlImplementation

УЯЗВИМАЯ РЕАЛИЗАЦИЯ
export const OpenUrlImplementation = createFunctionImplementation(OpenUrlApi, args => {
  if (args.url && typeof window !== 'undefined' && window.open) {
    window.open(args.url, '_blank');
  }
});
БЕЗОПАСНЫЙ ИСПРАВЛЕННЫЙ ВАРИАНТ
export const OpenUrlImplementation = createFunctionImplementation(OpenUrlApi, args => {
  if (args.url && typeof window !== 'undefined' && window.open) {
    const baseHref =
      typeof window.location !== 'undefined' && window.location.href
        ? window.location.href
        : undefined;
    let url: URL;
    try {
      url = baseHref ? new URL(args.url, baseHref) : new URL(args.url);
    } catch (e: any) {
      throw new A2uiExpressionError(`Invalid URL specified: ${args.url}`, 'openUrl', e);
    }

    // Строгий список протоколов: разрешены только HTTP и HTTPS.
    if (url.protocol !== 'https:' && url.protocol !== 'http:') {
      throw new A2uiExpressionError(`Unsupported URL scheme: ${url.protocol}`, 'openUrl');
    }

    // Всегда используйте noopener и noreferrer, чтобы открытая страница не могла управлять исходным окном.
    window.open(url.href, '_blank', 'noopener,noreferrer');
  }
});

Чек-лист по защите системы для инженеров

Источники