XSS in Outlook Adaptive Cards via Action.OpenUrl
While testing Adaptive Cards in Outlook, I discovered a cross-site scripting (XSS) vulnerability that allows an attacker to execute arbitrary JavaScript in the context of a victim’s Outlook inbox. The vulnerability exists in how Outlook handles the Action.OpenUrl action in Adaptive Cards, which does not properly validate URLs before passing them to window.open().
The Vulnerability #
The vulnerability exists in how Adaptive Cards handle the Action.OpenUrl action. This property is designed to open URLs when clicked, but it does not properly validate that the URL is actually a valid HTTP/HTTPS URL before passing it to window.open(). This allows an attacker to inject JavaScript code using the javascript: protocol scheme.
When a user clicks on an action button in an Adaptive Card, the url value from Action.OpenUrl is passed directly to window.open(), which will execute JavaScript payloads. Even though this execution occurs in a new window, the JavaScript can use window.opener to gain full access to the recipient’s inbox, allowing for session hijacking, data exfiltration, and other malicious activities.
The root cause is a combination of factors:
- The
Action.OpenUrlproperty does not validate URLs before use - The URL is passed directly to
window.open()without sanitization - No Content Security Policy (CSP) is in place to prevent JavaScript execution
- The
window.openerproperty allows the new window to access the parent window’s context
Affected Products #
- Outlook Web App: Vulnerable to XSS via
Action.OpenUrlin Adaptive Cards - Microsoft Teams: The payload is passed along, but JavaScript execution is blocked by CSP (partial mitigation)
- Other products using Adaptive Cards: Potentially affected depending on their implementation
The vulnerability affects any product that renders Adaptive Cards with Action.OpenUrl actions without proper URL validation.
How It Works #
The attack works by crafting an Adaptive Card with a malicious Action.OpenUrl that uses the javascript: protocol:
- Card Creation: An attacker creates an Adaptive Card with an
Action.OpenUrlaction containing ajavascript:URL - Card Delivery: The card is sent to a victim via email (or other delivery mechanism)
- User Interaction: When the victim clicks the action button, the URL is passed to
window.open() - JavaScript Execution: The JavaScript payload executes in a new window
- Context Access: The malicious JavaScript uses
window.openerto access the parent window (Outlook inbox)
Even though the JavaScript executes in a new window, window.opener provides full access to the parent window’s context, allowing the attacker to:
- Access the victim’s inbox
- Read email content
- Perform actions on behalf of the user
- Exfiltrate sensitive data
- Steal authentication tokens
Proof of Concept #
To demonstrate this vulnerability, you can use the Adaptive Cards MessageCard Playground:
Steps to Reproduce #
- Browse to https://messagecardplayground.azurewebsites.net/
- Authenticate with the application
- Send the following payload:
{
"$schema": "https://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": "10",
"items": [
{
"type": "Image",
"size": "auto",
"horizontalAlignment": "center",
"url": "https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/160/microsoft/106/hacker-cat_1f431-200d-1f4bb.png",
"altText": "Mostly cloudy"
},
{
"type": "TextBlock",
"horizontalAlignment": "center",
"wrap": false,
"color": "dark",
"text": "Test XSS"
}
],
"selectAction": {
"type": "Action.OpenUrl",
"title": "View Sunday",
"url": "javascript:alert(window.opener.location.href)"
}
}
]
}
]
}
- Click “Send Via Email” from the top bar to send this to yourself
- Check your email from Outlook web
- Click on the Action button
The JavaScript alert will execute, demonstrating that the XSS vulnerability is present. In a real attack, this could be replaced with malicious code that exfiltrates data or performs unauthorized actions.
Additional Payload (New Outlook) #
Interestingly, the following payload works on “the new Outlook” but is blocked in the other version:
{
"@type": "MessageCard",
"@context": "https://schema.org/extensions",
"summary": "Issue 176715375",
"themeColor": "0078D7",
"title": "Test XSS",
"sections": [
{
"text": "Test from OpenUri"
}
],
"potentialAction": [
{
"@type": "OpenUri",
"name": "View in GitHub",
"targets": [
{
"os": "default",
"uri": "javascript:alert(1)"
}
]
}
]
}
This demonstrates that the vulnerability exists in multiple card formats and affects different versions of Outlook differently.
Testing with Originator #
This vulnerability was tested not only by sending emails to myself, but also with an “originator” key, delivering the payload to anyone in my organization. This confirms that the vulnerability is not limited to “self” emails and can be exploited against any recipient.
The Impact #
This vulnerability is particularly dangerous because:
- Session hijacking: An attacker can steal authentication tokens and session cookies from the victim’s Outlook session
- Data exfiltration: The attacker can read email content, contacts, and other sensitive information from the victim’s inbox
- Unauthorized actions: The attacker can perform actions on behalf of the user, such as sending emails, deleting messages, or modifying settings
- Credential theft: The attacker could potentially access other services if the victim uses single sign-on (SSO)
- Persistent access: The attacker could establish persistent access to the victim’s account
The attack is especially concerning because it requires minimal user interaction; just clicking on a button in an email. The user doesn’t need to explicitly visit a malicious website or download a file; the vulnerability is triggered through normal email interaction.
Expected Fixes #
I would expect the following security measures to be implemented:
- URL Validation: Proper validation of the
Action.OpenUrlproperty to ensure it only accepts valid HTTP/HTTPS URLs - Protocol Whitelisting: Only allow
http://andhttps://protocols, explicitly blockingjavascript:,data:, and other potentially dangerous protocols - Content Security Policy: Implement CSP headers to prevent JavaScript execution even if validation fails
- Sanitization: Sanitize all user-controlled input before passing it to
window.open() - Same-Origin Restrictions: Consider using
rel="noopener"or similar mechanisms to preventwindow.openeraccess
Disclosure #
This vulnerability has been reported to Microsoft through their security program. The issue demonstrates the importance of proper input validation and the need for defense-in-depth security measures, including Content Security Policies, even when validation is in place.