Skip to content

Fix reflected XSS in echo_jwt and harden JWT handling#7

Open
Montana wants to merge 1 commit into
percolate:masterfrom
Montana:fix/reflected-xss-jwt-hardening
Open

Fix reflected XSS in echo_jwt and harden JWT handling#7
Montana wants to merge 1 commit into
percolate:masterfrom
Montana:fix/reflected-xss-jwt-hardening

Conversation

@Montana

@Montana Montana commented Jul 1, 2026

Copy link
Copy Markdown

Fix reflected XSS in /echo_jwt and harden JWT handling

What & why

The jwt query parameter is interpolated into the HTML response via str.format() with no escaping. Since a returned string is served as text/html, any markup in the parameter executes in the browser. The
invalid-token branch requires no secret, so this is an unauthenticated reflected XSS on all seven UI-extension routes:

/campaign?jwt=<script>alert(document.domain)</script>

Changes

  • HTML-escape the reflected token and the decoded payload with
    markupsafe.escape (closes the XSS).
  • Pin jwt.decode(..., algorithms=["HS256"]) so the token's own alg header
    can't select the algorithm (CWE-327 / the CVE-2024-33663 class of bug).
  • Compare the X-Perc-App-Secret header with hmac.compare_digest instead of
    != (constant-time).
  • Default app.run to debug=False, opt-in via FLASK_DEBUG — the README
    instructs exposing this via ngrok, and debug=True exposes the Werkzeug
    debugger (RCE).
  • Use request.path instead of request.base_url.split("/")[-1] for the
    callback name.
  • Bump python-jose (CVE-2024-33663, CVE-2024-33664) and Flask off the 2019
    pins, which also don't import on Python >= 3.10 (from collections import Mapping).

- HTML-escape the reflected token and decoded payload (closes unauthenticated
  reflected XSS on all UI-extension routes)
- Pin jwt.decode algorithms=["HS256"] to prevent algorithm confusion
- Use hmac.compare_digest for the X-Perc-App-Secret comparison
- Default app.run to debug=False, opt-in via FLASK_DEBUG
- Use request.path instead of base_url.split("/")[-1]
- Bump python-jose (CVE-2024-33663, CVE-2024-33664) and Flask off the 2019
  pins, which also fail to import on Python >= 3.10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant