FlawOpen

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

● CVE-2026-10032 · CVSS 9.3[1] · 심각
보안 연구 · FlawOpen

CVE-2026-10032: A2UI 에이전트 생성 버튼의 XSS

영향받는 버전에서 기본 활성화된 Basic Catalog의 openUrl은 에이전트 URL을 스킴 제한 없이 window.open에 전달했습니다. 권고문에 설명된 브라우저 origin 영향에는 사용자가 렌더링된 Button을 클릭해야 합니다. 0.10.2 이상으로 업그레이드하세요.[1]

CVSS 벡터CVSS: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
에이전트 생성 UI의 오픈소스 프로토콜 및 프로젝트입니다. 권고문은 web_core의 Basic Catalog를 다룹니다.[1]
기본 카탈로그
렌더링된 UI 동작에서 쓸 A2UI 기본 함수 모음이며 기본 활성화됩니다.[1]
함수 호출 동작
함수와 인수를 지정하는 선언형 UI 동작입니다. Button은 에이전트 URL로 openUrl을 호출할 수 있었습니다.[1], [2]
CWE-79
웹 페이지 생성 중 입력을 적절히 무력화하지 않은 약점 분류입니다. 권고문은 이 브라우저 삽입 문제에 지정했습니다.[1], [4]

프레임워크 매핑

  • 이 가이드에서 설명하는 약점의 CWE 참조: CWE-79

근본 원인 분석 (Root Cause)

Basic Catalog는 URL 인수를 신뢰할 수 없는 탐색 입력이 아닌 열 문자열로 취급했습니다. API는 문자열 형식만 확인했고 취약한 구현은 window.open(args.url, '_blank') 전에 URL 프로토콜을 제한하지 않았습니다. 에이전트 제어 Button.functionCall이 값을 sink까지 전달할 수 있었습니다. 사용자는 버튼을 클릭해야 합니다. A2UI 권고문은 피해 앱의 브라우저 origin에서 스크립트가 실행되는 영향을 설명합니다. 수정은 URL을 파싱하고 http: 및 https:만 허용한 뒤 noopener,noreferrer로 엽니다. 해당 sink 수정이며 에이전트 UI 전체의 안전성을 보장하지 않습니다.[1], [2]

CVE-2026-10032: 영향 버전과 동작 경계

배포 조건권고문 확인 사항방어 조치
기본 Basic Catalog를 사용하는 @a2ui/web_core 0.9.0, 0.9.1, 0.9.2, 0.10.0 또는 0.10.1.A2UI 권고문은 이 버전을 영향 대상으로 열거하고 Basic Catalog가 기본 활성화라고 합니다.0.10.2 이상으로 올리고 배포 앱의 버전을 확인하세요.
Button 호출이 에이전트 제어 데이터에서 오고 사용자가 클릭.권고문은 클릭에서 openUrl까지의 경로와 browser origin 영향을 설명합니다. 무클릭 취약점이 아닙니다.동작 인수를 신뢰하지 말고 URL 여는 함수에서 검증하세요.
A2UI React, Lit 또는 Angular renderer 사용.권고문은 이 통합을 포함하며 취약 경계는 web_core의 공유 Basic Catalog 동작입니다.패키지를 확인하고 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에 전달했습니다. 권고문은 피해 앱에서의 실행을 설명합니다.[1]

단계 5

수정 동작이 탐색 제한

수정은 URL을 해석하고 HTTP/HTTPS 외 프로토콜을 거부하며 noopener,noreferrer를 사용합니다. 0.10.2 이상으로 올리세요.[1], [2]

소스 코드 비교: 취약한 구현 vs 보안 패치

취약한 발췌는 A2UI 권고문이 지정한 구현에서 가져왔습니다. PR #1707은 URL을 파싱하고 HTTP/HTTPS만 허용하며 열린 페이지가 원래 페이지를 제어하거나 referrer를 받지 못하게 합니다. 프로젝트 타입과 import는 생략했으며 완전한 파일이나 PoC가 아닙니다.[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');
  }
});

엔지니어링 및 시스템 보안 강화 체크리스트

출처