Skip to content

Fix stored XSS in urldisplay and iconify template filters#344

Merged
milesmcc merged 1 commit intomasterfrom
claude/fix-xss-analytics-HAVim
Mar 15, 2026
Merged

Fix stored XSS in urldisplay and iconify template filters#344
milesmcc merged 1 commit intomasterfrom
claude/fix-xss-analytics-HAVim

Conversation

@milesmcc
Copy link
Copy Markdown
Owner

Summary

Fixes an unauthenticated stored XSS vulnerability in the dashboard. Attacker-controlled location and referrer values submitted via the public ingress endpoint were rendered into HTML attributes without escaping, allowing JavaScript execution in the admin's session.

Root cause

urldisplay (helpers.py:193) — interpolated the raw URL into single-quoted href='{url}' and title='{url}' attributes. A payload like http://x' onfocus='...' autofocus=' passed the startswith("http") check, then closed the href attribute early and injected new attributes.

iconify (helpers.py:184) — called by urldisplay with the same tainted input. urlparse().netloc preserves quote characters, and the netloc was inserted raw into a double-quoted src="..." attribute.

Fix

Apply escape() to the three unescaped interpolation points. This matches the existing escape(display_url) pattern already present on the same line. Django's escape() converts '' and "", preventing attribute break-out in both contexts.

Affected pages

  • /dashboard/service/<uuid>/ (location and referrer tables)
  • /dashboard/service/<uuid>/locations/

The urldisplay filter interpolated untrusted location/referrer values
directly into single-quoted href and title attributes without escaping.
An attacker could submit a location like "http://x' onfocus='...' autofocus='"
via the unauthenticated ingress endpoint, breaking out of the attribute
and executing arbitrary JavaScript when an admin viewed the dashboard.

The iconify filter had the same flaw: urlparse().netloc preserves quote
characters, and the netloc was inserted raw into a double-quoted src
attribute.

Both are fixed by applying escape() to the interpolated values, matching
the existing escape(display_url) pattern already present on the same line.
@milesmcc milesmcc merged commit 2298546 into master Mar 15, 2026
2 of 3 checks passed
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.

2 participants