Microsoft Azure Portal – Persistent Cross-Site Scripting

Item Comment
Software Microsoft Azure Portal
Type of Issue Persistent Cross-Site Scripting
Roles affected All
Privilege Escalation User to Administrator
CVSS High – 7.7
Credits Christian Becker & Sven Schlüter from Y-Security


The notification widget of the Microsoft Azure Portal does not encode certain HTML characters. This allows to inject HTML and JavaScript code into the Azure Portal, which is reflected for other users (of the same Azure Active Directory Tenant).

The Persistent Cross-Site Scripting attack would allow to read and modify the content of the logged in user and provide a possibility to escalate privilege to those of a Portal Administrator.


Steps to reproduce

Multiple ways to inject JavaScript code exists and we will show as an example how a standard user can attack an administrator in a Cross-Site Scripting attack:

1st: Steps for the Attacker (low privileged user)

  • Open
  • Browse to „Azure Active Directory“
  • Go to „Groups“
  • Select „New Group“
  • Provide a „Group name“ of „Y<a target=“_parent“ href=“javascript:alert(document.domain)//mailto:“>Y-Security„ and hit „Create“

2nd: Steps for the Administrator to trigger the attack

  • Open
  • Browse to „Azure Active Directory“
  • Go to „Users“ and click any user
  • Under „Manage –> Groups“ click „Add memberships“
  • Add the previous created group „Y<a target=“_parent“ href=“javascript:alert(document.domain)//mailto:“>Y-Security„ by clicking on it and hit „Select“

The Microsoft Azure Portal automatically confirms the action with a notification on the upper right, which was found to render certain HTML tag:

Automatic notification of added group membership

The malicious code is also displayed in the Notifications panel (bell) and placed persistent in the notification widget:

Rendered payload in Notifications widget

The JavaScript code entered as part of the payload is executed whenever the text is clicked:

Executed JavaScript payload on

The JavaScript code is executed every time the group is used and gets displayed in the notification bar – making it a persistent issue.

Details of the attack vector

In the below we have split up the attack vector to explain it in more detail:

Y<a target="_parent" href="javascript:alert(document.domain)//mailto:">Y-Security
Injection Description
Y A single character is needed before an HTML element can be used
<a Opening for the a element
target=“_parent“ By default the _target would be „_blank“ and hence not executing our code
href=“ Opening for the a href attribut
javascript:alert(document.domain) JavaScript code to display the current domain in an alert box
//mailto: The double slash is required to end the JavaScript command/comment out all further code. The mailto: is required to bypass the filter
href=“ Closing href attribute value
>Y-Security Closing the A Element and appending a String

Root Cause – Bypass of Allowed URL handlers

We have bypassed the allowed URL handlers by appending a mailto:. The following code snippet is from

var d = MsPortalFx.Base.Diagnostics, f = /^(vstfs:|ftp:|ftps:|sftp:|storageexplorer:|adlalink:|adl:|asalink:|vscode:|vsweb:|azuredatastudio:|bfcomposer:|)\/\/|mailto:/, l = /^#(allservices|asset|blade|create|dashboard|home|menu|resource)\b/, e = /^#/, a = /^(data:image)\//;

The regular expression for all allowed protocol handlers requires „to start with one of the defined URL handlers followed by a double slash“, for example „ftp://“. mailto: is the only protocol handler which does not require a double slash and therefore is shown in an extra list. The „starts-with“ (`^`) regular expression is missing: |mailto:. That allowed us to place the mailto: anywhere in the URI scheme and still get a valid response from the filter/regular expression.


We believe the URL handler bypass for mailto: is generic and could be abused in other places as well. The root issue relies in the notification widget, but can be triggered also when:

  • Adding a new Administrative unit with a malicious name (like the above a Element) and assigning that unit to a group
  • Adding a new user with a malicious display name (like the above a Element) and adding that user to a group

Another example of this generic injection can be found under using the Create Key Vault option with the payload in the Key vault name. The injection is reflected in the error message.


The mailto: filter should be changed to make sure it needs to be at the start of the string. This would already remediate the injection of JavaScript code in this instance. To mitigate against HTML injection it is recommended to perform HTML encoding.

Fix (10.09.2021)

The single character fix to mitigate the issue has been rolled out on the 9th of September 2021:

var d = MsPortalFx.Base.Diagnostics, f = /^(vstfs:|ftp:|ftps:|sftp:|storageexplorer:|adlalink:|adl:|asalink:|vscode:|vsweb:|azuredatastudio:|bfcomposer:|ms-quick-assist:|ms-remote-assist:|)\/\/|^mailto:/, l = /^#(allservices|asset|blade|create|dashboard|home|menu|resource)\b/, e = /^#/, a = /^(data:image)\//;

Now, it is verified that mailto is at the start of the URL scheme which prevents the above payload from being executed. It is still possible to inject some HTML characters but we couldn’t identify another vector to bypass the security controls and inject JavaScript within the time spend on the application.


We have disclosed the issue to Microsoft MSRC and the public with the following timeline:

Date Comment
19.08.2021 Issue discovered
20.08.2021 Issue exploitability verified
20.08.2021 Issue opened with Microsoft MSRC
08.09.2021 Behavior confirmed & Investigation Started
09.09.2021 Issue remediated
10.09.2021 Added mitigation description & internal release
15.09.2021 Coordinated Public Disclosure

Disclosure Policy

Please note: The vulnerability is subjected under the Y-Security Disclosure policy that be found here: