flawopen.com/Teardowns/cve-2026-10032-a2ui-agent-button-xss
CVE-2026-10032: XSS через кнопки A2UI, созданные агентом
В уязвимых версиях openUrl из Basic Catalog по умолчанию передавал URL агента в window.open без ограничения схемы. Для описанного в уведомлении воздействия на origin браузера пользователь должен был нажать Button; обновитесь до 0.10.2 или новее.[1]
Представьте киоск, где помощник добавляет кнопку, а адрес записан на переданной им карточке. Киоск проверяет наличие адреса, но не ведёт ли он на обычную веб-страницу. Посетителю нужно нажать кнопку; без правила браузер может принять адрес за инструкцию самому киоску. Исправление разбирает адрес и принимает только HTTP- или HTTPS-направления.[1], [2]
Ключевые понятия и термины
A2UI- Протокол и проект с открытым кодом для интерфейсов агентов; уведомление относится к Basic Catalog в web_core.[1]
Базовый каталог- Встроенный набор функций A2UI; по уведомлению, включён по умолчанию.[1]
Связи со стандартами
- Ссылка 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. |
Пошаговый сценарий атаки
Агент задаёт действие Button
Данные A2UI могут задавать Button с вызовом функции и аргументами. Считайте действия агента недоверенными.[1]
Basic Catalog разрешает openUrl
Basic Catalog предоставляет openUrl; схема требует строку, но код не ограничивал схему URL.[1]
Действие достигает window.open
До патча openUrl передавал строку в window.open без проверки протокола. Уведомление описывает выполнение в origin приложения-жертвы.[1]
Исходный код: Уязвимый 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');
}
});
Чек-лист по защите системы для инженеров
- ✓Обновите все зависимости @a2ui/web_core до 0.10.2 или новее; проверьте lockfile и production bundle.[1]
- ✓Проверьте приложения с Basic Catalog и React-, Lit- или Angular-рендерерами; могут ли данные агента задавать вызовы Button?[1]
- ✓Проверяйте URL у точки навигации: разберите и разрешите его, затем допускайте только схемы HTTP/HTTPS; не проверяйте префикс строки.[2]
- ✓Открывайте внешние адреса с
noopener,noreferrer; политику согласия применяйте отдельно, поскольку она решает другую задачу.[2] - ✓Проверьте разрешение HTTP/HTTPS и относительных URL и отклонение ошибочных адресов и схем кроме HTTP(S) до вызова
window.open.[2] - ✓Считайте подписи, адреса и аргументы агента недоверенными; проверяйте действие у sink, не полагаясь на очистку рендерером.[1], [2]