a2ui-project / a2ui-project/a2ui
[BUG]: `createSurface.theme` values stored without validation and consumed as CSS values
- 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
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