Skip to content

web: escape values interpolated into the landing page - #437

Open
mrueg wants to merge 1 commit into
prometheus:masterfrom
mrueg:fix/landing-page-html-escaping
Open

web: escape values interpolated into the landing page#437
mrueg wants to merge 1 commit into
prometheus:masterfrom
mrueg:fix/landing-page-html-escaping

Conversation

@mrueg

@mrueg mrueg commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

NewLandingPage renders the page with text/template, so nothing it interpolates is escaped. Every field the template reads reaches the browser verbatim — Description, Version, each link's Text, Address and Description, and every form input's Value, Placeholder, Name and Type — including inside the href="…" and value="…" attributes. An exporter that puts a probe target, a query parameter or any other non-constant value on its landing page therefore has an injection point.

Reproduced against master: a Description of </div><script>alert(1)</script> and a link Text of "><script>alert(2)</script> both appear byte-for-byte in the served body.

Change

Render with html/template, which escapes each value for the context it appears in. The two fields documented as carrying markup keep doing so by becoming template.HTML and template.CSS.

The generated stylesheet is still built with text/template: its output is injected into the page as a template.CSS value, and running it through html/template would escape it for an HTML context rather than a CSS one.

Ordinary link addresses are unaffected — /probe?module=http_2xx&target=example.com is written into the attribute as …module=http_2xx&amp;target=example.com, which browsers decode back to a single &. There is a test covering exactly this.

Compatibility

This changes three LandingConfig fields from string to template.HTML/template.CSS. Callers assigning a string literal are unaffected, since an untyped constant converts on assignment; callers assigning a string variable need an explicit conversion.

Tests

landing_page.go had 0% coverage. Added tests for escaping, the two verbatim fields, link query strings, the generated stylesheet, and the handler's 404 path. The escaping test fails against master.

🤖 Generated with Claude Code

NewLandingPage rendered the page with text/template, so nothing it
interpolated was escaped. Every field the template reads reaches the
browser verbatim: Description, Version, each link's Text, Address and
Description, and every form input's Value, Placeholder, Name and Type,
including inside the href="..." and value="..." attributes. An exporter
that puts a probe target, a query parameter or any other non-constant
value on its landing page therefore has an injection point.

Render the page with html/template instead, which escapes each value for
the context it appears in. The two fields that are documented as carrying
markup keep doing so by becoming template.HTML and template.CSS, which
html/template emits verbatim by design.

The generated stylesheet is still built with text/template: its output is
injected into the page as a template.CSS value, and running it through
html/template would escape it for an HTML context rather than a CSS one.

Ordinary link addresses are unaffected. A query string such as
/probe?module=http_2xx&target=example.com is written into the attribute as
...module=http_2xx&amp;target=example.com, which browsers decode back to a
single "&" when following the link.

This changes the type of three LandingConfig fields from string to
template.HTML or template.CSS. Callers assigning a string literal are
unaffected, since an untyped constant converts on assignment; callers
assigning a string variable need an explicit conversion.

landing_page.go had no test coverage at all, so add tests for escaping,
for the two verbatim fields, for link query strings, for the generated
stylesheet, and for the handler's 404 path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Manuel Rüger <manuel@rueg.eu>
@mrueg
mrueg force-pushed the fix/landing-page-html-escaping branch from 867d6c4 to 88bf0fa Compare September 2, 2026 13:44
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