a2ui-project / a2ui-project/a2ui

[BUG]: `createSurface.theme` values stored without validation and consumed as CSS values

Open
#2,293 2 comments 0 reactions 1 assignee Claimed by @Varun-S10 View on GitHub
P2 status: first-line-handled status: needs review type: bug
Dominant language
TypeScript
Stars
16.4k
Forks
1.3k
Avg merge
2d 13h
Merged PRs (30d)
134

Description

# `createSurface.theme` values stored without validation and consumed as CSS values

Repository: https://github.com/a2ui-project/a2ui
Affected package: `@a2ui/web_core` (verified on 0.10.6); observable in the Angular renderer
CWE: CWE-20 (Improper Input Validation) with CSS value injection consequence

## Summary

The specification states that theme fields such as `primaryColor` must be hexadecimal color codes, but no layer enforces this. The message envelope declares `theme: z.any()`, the surface model stores it verbatim, and the Angular renderer pipes it into a CSS custom property that a Button consumes via the `background` shorthand — where `url(...)` is valid.

## Affected code

- `renderers/web_core/src/v0_9/schema/server-to-client.ts:33` — `theme: z.any()`
- `renderers/web_core/src/v0_9/state/surface-model.ts:57-65` — stored verbatim (themeSchema is only broadcast in capabilities)
- `renderers/angular/.../basic-catalog-component.ts:69-72` — `@HostBinding('style.--a2ui-color-primary')`
- `renderers/angular/.../button.component.ts:77` — `background: var(--a2ui-color-primary)` (shorthand)

## Observed behavior

- `createSurface` with `theme: {primaryColor: "url(https://attacker.example/beacon)"}` is accepted and stored verbatim through the published package pipeline (no error).
- In the Angular renderer, the button's computed `background-image` contains the injected URL, and one cross-origin request was captured via the Performance API.
- The Lit renderer consumes `background-color`, where `url()` is inert; only the Angular shorthand path is affected.

## Impact

An agent can cause cross-origin requests from the host origin (disclosing IP/User-Agent/timing) and overlay attacker-chosen imagery on buttons (UI spoofing). No script execution was achieved — the value remains contained within a CSS declaration.

## Suggested remediation

Validate theme on receipt: `themeSchema.parse(theme)` with a strict hex/named-color allowlist.

Contributor guide

Open the contributing guide

Research direction

The issue points to specific files: server-to-client.ts (schema), surface-model.ts (storage), basic-catalog-component.ts (binding), and button.component.ts (consumption). Start by examining the Zod schema in server-to-client.ts and the theme storage in surface-model.ts. The fix involves adding validation with a strict color allowlist (hex or named colors) before storage. Test by creating a surface with an invalid theme value and ensuring it is rejected or sanitized.

Written by the indexing model from the issue text.

Assessment

Tech stack
angular, css, typescript
Domain
frontend, security
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.