flawopen.com/Teardowns/cve-2026-10032-a2ui-agent-button-xss
CVE-2026-10032 : XSS dans les boutons A2UI générés par un agent
Dans les versions touchées de @a2ui/web_core, openUrl du Basic Catalog par défaut transmettait une URL de l’agent à window.open sans limiter son schéma. Une personne devait cliquer sur le Button rendu pour provoquer l’impact sur l’origine du navigateur décrit dans l’avis ; passez à 0.10.2 ou ultérieur.[1]
Imaginez une borne où un assistant place un bouton et inscrit sa destination sur une carte qu’il fournit. La borne vérifie qu’il y a une adresse, pas qu’elle mène à une page Web ordinaire. Un visiteur doit toujours appuyer dessus ; sans règle de destination, le navigateur peut toutefois interpréter l’adresse comme une instruction pour la borne. Le correctif analyse l’adresse et n’accepte que HTTP ou HTTPS.[1], [2]
Concepts Clés et Termes
A2UI- Protocole et projet open source pour les interfaces générées par agents ; l’avis vise l’action Basic Catalog du package web_core.[1]
Catalogue de base- Ensemble intégré de fonctions A2UI pour les actions de l’interface rendue ; l’avis indique qu’il est activé par défaut.[1]
Correspondances de référentiels
- Référence CWE pour la faiblesse décrite dans ce guide : CWE-79
Analyse de Cause Racine
L’implémentation Basic Catalog touchée traitait l’argument URL comme une chaîne à ouvrir, et non comme une entrée de navigation non fiable soumise à une politique de schéma. L’API vérifiait le type chaîne, mais le code vulnérable ne limitait pas le protocole avant window.open(args.url, '_blank'). Un Button.functionCall contrôlé par l’agent pouvait transmettre la valeur au sink. Une personne devait cliquer sur le bouton rendu ; l’avis A2UI décrit l’exécution de script dans l’origine de l’application victime. Le correctif amont analyse la valeur, n’autorise que http: et https:, puis ouvre l’URL normalisée avec noopener,noreferrer. Il corrige ce point de navigation sans garantir la sûreté de toute interface générée par agent.[1], [2]
CVE-2026-10032 : versions touchées et limite de l’action
| Condition de déploiement | Éléments confirmés par l’avis | Mesure défensive |
|---|---|---|
| @a2ui/web_core 0.9.0, 0.9.1, 0.9.2, 0.10.0 ou 0.10.1 avec Basic Catalog par défaut. | L’avis répertorie ces versions et indique que Basic Catalog est activé par défaut. | Passez à 0.10.2 ou ultérieur et vérifiez la version déployée. |
| Un appel de fonction Button vient de données A2UI contrôlées par agent et une personne clique. | L’avis décrit le clic vers openUrl et l’impact sur l’origine navigateur ; ce n’est pas du zero-click. | Traitez les arguments comme non fiables et validez-les dans la fonction qui ouvre l’URL. |
| L’application utilise un moteur React, Lit ou Angular d’A2UI. | L’avis inclut ces intégrations ; la limite vulnérable est l’action Basic Catalog partagée dans web_core. | Vérifiez le package et mettez à jour web_core ; un réglage du renderer ne supprime pas forcément l’action. |
| L’application exécute @a2ui/web_core 0.10.2 ou ultérieur. | Les mainteneurs désignent 0.10.2 comme corrigé : analyse URL, autorisation HTTP/HTTPS et noopener,noreferrer. | Gardez des tests pour les schémas valides et invalides et examinez tout remplacement personnalisé de openUrl. |
Déroulement de l'Attaque Étape par Étape
Un agent fournit une action Button
Les données UI A2UI peuvent définir un Button avec appel de fonction et arguments. Traitez comme non fiable une action venant d’un agent.[1]
Basic Catalog résout openUrl
Le Basic Catalog par défaut expose openUrl ; le schéma exige une chaîne, mais le code vulnérable ne limitait pas le schéma URL.[1]
L’action atteint window.open
Avant le correctif, openUrl transmettait la chaîne à window.open sans analyser ni autoriser le protocole. L’avis décrit l’exécution dans l’origine de l’application victime.[1]
Code Source : Vulnérable vs Sécurisé
L’extrait vulnérable vient de l’implémentation citée dans l’avis A2UI. L’extrait corrigé représente le changement amont de la PR #1707 : analyser et résoudre l’adresse, n’autoriser que HTTP/HTTPS et empêcher la page ouverte de contrôler la page source ou de recevoir le référent. Types et imports sont omis ; ce ne sont ni des fichiers complets ni une preuve de concept.[1], [2]
Extrait source: 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);
}
// Liste stricte des protocoles : seuls HTTP et HTTPS sont autorisés.
if (url.protocol !== 'https:' && url.protocol !== 'http:') {
throw new A2uiExpressionError(`Unsupported URL scheme: ${url.protocol}`, 'openUrl');
}
// Utilisez toujours noopener et noreferrer pour empêcher la page ouverte de contrôler la fenêtre d’origine.
window.open(url.href, '_blank', 'noopener,noreferrer');
}
});
Liste de Contrôle de Sécurité pour l'Ingénierie
- ✓Mettez à niveau toutes les dépendances directes et transitives de @a2ui/web_core vers 0.10.2 ou ultérieur ; vérifiez le lockfile et le bundle de production.[1]
- ✓Inventoriez les applications avec Basic Catalog et les moteurs React, Lit ou Angular ; vérifiez si les données agent peuvent définir des appels de fonction Button.[1]
- ✓Validez l’URL au point de navigation : analysez-la et résolvez-la d’abord, puis autorisez seulement des schémas approuvés comme HTTP et HTTPS ; évitez les contrôles de préfixe.[2]
- ✓Ouvrez les destinations externes avec
noopener,noreferreret appliquez séparément la politique de consentement/navigation du produit ; ces mesures couvrent des risques distincts.[2] - ✓Testez la résolution des URL HTTP/HTTPS et relatives prévues, et le rejet des URL mal formées ou de tout schéma non HTTP(S) avant
window.open.[2] - ✓Traitez libellés, destinations et arguments de fonction de l’agent comme non fiables ; validez chaque action au sink sans supposer que le renderer assainit les données.[1], [2]