HexBrain

Mozilla · Report #3988961

Stored XSS on the public Pontoon dashboards: the latest-activity tooltip re-parses a contributor's account address as HTML

Validstatus
highseverity
$3,000bounty
61upvotes
14 Oct 2026disclosed

Summary

Summary

Pontoon's latest-activity tooltip on its public dashboards built its markup by concatenating contributor-supplied data-* values into a string and handing it to jQuery's .after(). Only the translation text was encoded. The server escaped the values into the attributes, but the browser decodes attributes before jQuery reads them, so the markup came back raw.

A contributor with no display name is shown by their account email address, and Pontoon's local signup accepted an address like "<script>alert(document.domain)</script>x"@example.org. One signup and one ordinary suggestion put that script on a public dashboard, where it ran in the session of anyone who hovered the cell, signed in or not. Before the report was filed it fired on pontoon.allizom.org, which was serving no Content-Security-Policy after a django-csp 4.0 upgrade dropped the policy.

In a translator's session the script could approve the attacker's own suggestion, and in a locale manager's it could add the attacker to that locale's managers group, a membership that would outlive every session involved.

Two changes closed the attack path on Mozilla's instance, and a third removed the sink:

Self-hosted Pontoon instances should be on v2026.10.08 or later. Removing signup doesn't cover instances using other sign-in methods, which can still set the displayed name.

Summary

Pontoon's latest-activity tooltip on its public dashboards built its markup by concatenating contributor-supplied data-* values into a string and handing it to jQuery's .after(). Only the translation text was encoded. The server escaped the values into the attributes, but the browser decodes attributes before jQuery reads them, so the markup came back raw.

A contributor with no display name is shown by their account email address, and Pontoon's local signup accepted an address like "<script>alert(document.domain)</script>x"@example.org. One signup and one ordinary suggestion put that script on a public dashboard, where it ran in the session of anyone who hovered the cell, signed in or not. Before the report was filed it fired on pontoon.allizom.org, which was serving no Content-Security-Policy after a django-csp 4.0 upgrade dropped the policy.

In a translator's session the script could approve the attacker's own suggestion, and in a locale manager's it could add the attacker to that locale's managers group, a membership that would outlive every session involved.

Two changes closed the attack path on Mozilla's instance, and a third removed the sink:

Self-hosted Pontoon instances should be on v2026.10.08 or later. Removing signup doesn't cover instances using other sign-in methods, which can still set the displayed name.

How it was found

The write-up for this report has not been downloaded yet, or the program disclosed it without one. Read it on HackerOne.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original