Skip to content

fix(ui): consolidate HTML escaping into one helper that escapes single quotes - #122

Merged
mrorigo merged 1 commit into
mainfrom
fix/ui-shared-escape-helper
Oct 4, 2026
Merged

mrorigo merged 1 commit into
mainfrom
fix/ui-shared-escape-helper

Conversation

@mrorigo

@mrorigo mrorigo commented Oct 3, 2026

Copy link
Copy Markdown
Member

The UI carried eleven copies of escapeHtml. Ten replaced & < > " but not ', and all ten are interpolated into single-quoted JavaScript string literals inside HTML attributes, e.g. onclick="window.app.deleteAlias('tool', '${escapeHtml(alias)}')". A value containing ' closes that JavaScript literal early so the remainder parses as code. An alias, profile name, server id, task id or capability key containing '); window.app.someMethod(' executed script in the control-plane origin, where it could reach any window.app method including the approval and policy functions. components/audit.ts already had a correct copy escaping the single quote; that implementation moves to ui/src/escape.ts and is imported from all eleven modules. Verified both directions with a harness reproducing the aliases.ts:29 render. No committed test: the repo has no UI test runner.

…e quotes

The UI carried eleven copies of `escapeHtml`. Ten of them replaced `&`,
`<`, `>` and `"` but not `'`, and every one of those ten is interpolated
into a single-quoted JavaScript string literal inside an HTML attribute,
for example:

    onclick="window.app.deleteAlias('tool', '${escapeHtml(alias)}')"

A value containing `'` closes that JavaScript string literal early, so the
remainder of the value is parsed as code. HTML escaping was applied and was
nonetheless insufficient, because it does not neutralise the quoting
character of the context the value actually lands in.

An alias, profile name, server id, task id, or capability key containing
`'); window.app.someMethod('` therefore executed arbitrary script in the
control-plane origin, where it could call any `window.app` method including
the approval and policy functions.

`components/audit.ts` already had a correct copy that escaped the single
quote. Move that implementation to `ui/src/escape.ts` and import it from
all eleven modules, deleting the ten unsound copies.
@mrorigo
mrorigo merged commit 0d8ff7c into main Oct 4, 2026
10 checks passed
@mrorigo
mrorigo deleted the fix/ui-shared-escape-helper branch October 4, 2026 00:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant