a2ui-project / a2ui-project/a2ui

[BUG]: Unhandled TypeError in Icon Component due to Missing Type Verification

オープン
#2,578 コメント 1 件 リアクション 0 件 担当者 1 名 @Varun-S10 が担当を希望しています GitHub で見る
P2 status: first-line-handled status: needs review type: bug
主要言語
TypeScript
スター
16.4k
フォーク
1.3k
平均マージ
2日 13時間
マージ済み PR(30日)
134

説明

# Location
renderers/angular/src/v0_8/components/icon.ts:35

# Description
The resolvedName computed signal in the Angular Icon component resolves its name property dynamically from the agent-controlled DataModel. It fails to verify if the resolved rawName is a string before passing it to toSnakeCase(). If a malicious or compromised agent provides a data model path that resolves to a non-string value such as an object, array, or number, the replace() method called inside toSnakeCase() will throw a TypeError. This unhandled exception during Angular's change detection cycle aborts rendering and causes a Denial of Service (crash) for the chat UI.

# Impact
Denial of Service (UI crash / Component rendering failure)

# Mitigation
Verify the type of rawName before processing. Modify the resolvedName computed signal to check if typeof rawName === 'string', or cast it using String(rawName) before passing it to toSnakeCase().

# Reproduction Steps
Send an A2UI message that defines an icon component.
Set the name property to resolve from a path in the DataModel that contains an object or an array (e.g., {"path": "/my_array"}).
The component attempts to render, and rawName.replace throws a TypeError, breaking the Angular change detection loop for the view.

# Evidence
```
protected readonly resolvedName = computed(() => {
const rawName = this.resolvePrimitive(this.name());
if (!rawName) return '';
return this.toSnakeCase(rawName); // rawName can be an object or number if resolved from DataModel
});

private toSnakeCase(str: string): string {
return str
.replace(/^[A-Z]/, letter => letter.toLowerCase()) // Throws TypeError if str is not a string
.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
}
```

# Reasoning
The finding correctly identifies that the A2UI v0.8 Angular Icon component dynamically resolves its name property from the DataModel via resolvePrimitive(this.name()). Since the Agent is untrusted (Trust Boundary 1) and can control the DataModel contents via updateDataModel messages, it can supply a path that resolves to a non-string type, such as an array ([]), object ({}), or number (123).

When rawName is an array or object, it passes the truthiness check (if (!rawName) return '';) but causes this.toSnakeCase(rawName) to throw a TypeError because non-string primitives do not have a .replace() method.

In Angular, an unhandled exception thrown synchronously inside a computed() signal's calculation aborts the change detection cycle, leading to a rendering crash for the component and a potential freeze of the host product's UI. This strictly aligns with the A2UI Threat Model for Malicious Agents (A1), whose stated goal includes a 'main-thread freeze of embedding product', and the fact that framework binders are considered CRITICAL for availability. The issue was mitigated in the v0.9 IconComponent (typeof name !== 'string'), but due to A2UI's multi-version co-existence, the v0.8 implementation remains vulnerable.

# Verification Hints
Construct an Agent response with an icon component where name points to a data model path: {\"type\": \"icon\", \"id\": \"test-icon\", \"name\": {\"path\": \"/bad_data\"}}.
Supply a DataModel update setting /bad_data to an array, e.g., [1, 2, 3].
Render the v0_8 Angular Icon component and trigger Angular change detection (e.g., fixture.detectChanges()).
Observe that a TypeError: rawName.replace is not a function is thrown and the component fails to render, confirming the DoS vector.

コントリビューションガイド

コントリビューションガイドを開く

評価

この issue はまだ評価されていません。

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。