web: escape values interpolated into the landing page - #437
Open
mrueg wants to merge 1 commit into
Open
Conversation
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&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
force-pushed
the
fix/landing-page-html-escaping
branch
from
September 2, 2026 13:44
867d6c4 to
88bf0fa
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
NewLandingPagerenders the page withtext/template, so nothing it interpolates is escaped. Every field the template reads reaches the browser verbatim —Description,Version, each link'sText,AddressandDescription, and every form input'sValue,Placeholder,NameandType— including inside thehref="…"andvalue="…"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
Descriptionof</div><script>alert(1)</script>and a linkTextof"><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 becomingtemplate.HTMLandtemplate.CSS.The generated stylesheet is still built with
text/template: its output is injected into the page as atemplate.CSSvalue, and running it throughhtml/templatewould escape it for an HTML context rather than a CSS one.Ordinary link addresses are unaffected —
/probe?module=http_2xx&target=example.comis written into the attribute as…module=http_2xx&target=example.com, which browsers decode back to a single&. There is a test covering exactly this.Compatibility
This changes three
LandingConfigfields fromstringtotemplate.HTML/template.CSS. Callers assigning a string literal are unaffected, since an untyped constant converts on assignment; callers assigning astringvariable need an explicit conversion.Tests
landing_page.gohad 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