Persistent XSS in milestones data-milestone-id attribute when payload is using HTML-entities
The milestone_select.js located in app/assets/javascripts/milestone_select.js suffers from a stored XSS issue in the renderRow-function. The issue is that the data-milestone-id-attribute is containing the name of the milestone, but is not sanitized properly:
The issue is currently on line #98 (closed): https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/milestone_select.js#L98
renderRow: milestone => `
<li data-milestone-id="${milestone.name}">
<a href='#' class='dropdown-menu-milestone-link'>
${_.escape(milestone.title)}
</a>
</li>
`,
As you see, the title is escaped but the name is not, but they are the same really:
Now, this is not possible to do with normal angle-brackets, however, due to the passing of data, using HTML-entities for the payload will trigger this issue when creating a Milestone with the following name:
'"><img src=x onerror=alert(document.domain)>
This seems to be some form of issue with it server side, as the milestones.json actually contains escaped real angle-bracket characters:
"name":"'\"\u003e\u003cimg src=x onerror=alert(document.domain)\u003e"
PoC
- Create a new milestone at:
/project-name/milestones - Name the milestone:
'"><img src=x onerror=alert(document.domain)> ```  - Save, now go to
/project-name/issues, pressNew issue - Click on the Milestone-selector:
the javascript will trigger:
This happens on every place where the milestone-selector exists, it's all over the app.
Impact
The stored XSS is triggering for anyone, also triggering on gitlab.com, and it can trigger on public repos. You could easily build a PoC that would modify the email address of the current user stealing their CSRF-token as soon as the script triggers.



