Safeguard
Application Security•

CWE-652 XQuery Injection: How It Works and How to Prevent It

Building XQuery strings from user input lets attackers change the query itself. Bind variables and validate input to keep data separate from logic.

Safeguard Security Team
2 min read

CWE-652 is injection against XML databases. An application builds an XQuery expression by joining in external input without neutralizing it, so the attacker controls the structure of the query. It is the XML cousin of SQL injection and affects any service that queries an XML store.

How it happens

The code concatenates a request value into a query string:

// Vulnerable: input becomes part of the query text
String q = "for $u in doc('users.xml')//user "
         + "where $u/name = '" + name + "' return $u";

A name such as x' or '1'='1 changes the where clause so it matches every user. MITRE describes the net effect: the attacker controls the information selected from the XML database and may use that to control application flow, modify logic, retrieve unauthorized data or bypass checks such as authentication.

What an attacker gains

The record lists one consequence, confidentiality: reading sensitive information from the XML database. The extended description adds logic changes and authentication bypass as possible outcomes.

How to find it

The record lists no detection methods. Search for places where query strings are built with concatenation or string formatting. Test inputs containing quotes and query keywords against each parameter and watch for changed results or errors.

How to fix it

MITRE gives two implementation mitigations.

  1. Use parameterized queries. This keeps the data plane separate from the control plane.
  2. Validate user input properly. Reject data where appropriate, filter where appropriate and escape where appropriate, so input used in the query is safe in that context.
// Safer: external variable bound as data
String q = "declare variable $name external; "
         + "for $u in doc('users.xml')//user where $u/name = $name return $u";
XQPreparedExpression e = conn.prepareExpression(q);
e.bindString(new QName("name"), name, null);

Quick check

Why does a bound variable stop injection?

The value is passed as data, never parsed as part of the query, so quotes in it cannot change the query's structure.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.