HIGH xpath injectionactix

Xpath Injection in Actix

How Xpath Injection Manifests in Actix

XPath injection in Actix applications typically occurs when user-supplied data is incorporated into XPath queries without proper sanitization. In Actix, this vulnerability often appears in routes that process XML data or interact with XML-based storage systems.

The most common pattern involves Actix handlers that accept query parameters and use them to construct XPath expressions. For example, an endpoint that searches XML data based on user input might look like this:

async fn search_user(data: web::Data<AppState>, query: web::Query<UserQuery>) -> impl Responder {
    let xpath = format!("/users/user[name='{}']", query.name);
    let result = execute_xpath(data.xml_store.clone(), xpath).await;
    HttpResponse::Ok().json(result)
}

The vulnerability becomes apparent when examining how the XPath string is constructed. An attacker can craft a name parameter like admin' or '1'='1, which would produce:

/users/user[name='admin' or '1'='1']

This expression would match all user nodes, bypassing authentication or authorization checks.

In Actix applications, XPath injection often appears alongside XML parsing libraries like roxmltree or xml-rs. The injection point typically exists where user input is concatenated directly into XPath strings without parameterization.

Another Actix-specific manifestation occurs in middleware that processes XML-based API requests. Consider a middleware that extracts authentication information from XML headers:

async fn extract_auth(xml: &str) -> Result<AuthInfo> {
    let xpath = format!("/request/auth[user='{}']", get_user_from_header());
    // Execute XPath query
    let result = execute_xpath(xml, xpath).await?;
    // Process result
    Ok(result)
}

Actix's async/await pattern can make these vulnerabilities harder to spot, as the injection point might be separated from the query execution by async boundaries.

Actix-Specific Detection

Detecting XPath injection in Actix applications requires examining both the code structure and runtime behavior. middleBrick's scanner identifies these vulnerabilities through several Actix-specific detection mechanisms.

The scanner analyzes Actix route handlers that accept query parameters or JSON bodies, looking for patterns where string interpolation creates XPath expressions. It specifically flags cases where:

  • User input from web::Query, web::Json, or web::Path is directly interpolated into XPath strings
  • XML parsing libraries are imported alongside Actix route handlers
  • XPath expressions are constructed using format! or string concatenation

middleBrick runs active probing against Actix endpoints, testing for XPath injection by submitting payloads designed to extract information from XML documents. For instance, it might submit:

' or 1=1 or 'a'='a

or more complex payloads that attempt to extract specific XML nodes or attributes.

The scanner also examines Actix middleware chains, as XPath injection vulnerabilities often hide in middleware that processes XML requests before they reach the main handler. It looks for middleware that:

  • Parses XML request bodies
  • Constructs XPath queries from request headers or parameters
  • Performs XML-based authentication or authorization

For Actix applications using actix-web-actors or WebSocket handlers, middleBrick tests XML-based message formats that might be vulnerable to XPath injection when processed by the actor system.

The detection process includes static analysis of the Rust codebase to identify imports of XML processing libraries like roxmltree, xml-rs, or quick-xml in combination with Actix route handlers. This helps pinpoint the most likely locations for XPath injection vulnerabilities.

Actix-Specific Remediation

Remediating XPath injection in Actix applications involves both input validation and safe query construction. The most effective approach is to use parameterized XPath queries when available, though this requires specific XML processing libraries.

For Actix applications using roxmltree, you can use safe query construction:

use roxmltree;

async fn safe_search(xml: &str, name: &str) -> Result<Vec<User>> {
    let doc = roxmltree::Document::parse(xml)?;
    
    // Use safe navigation instead of string interpolation
    let nodes = doc
        .descendants()
        .filter(|n| n.tag_name().name() == "user")
        .filter(|n| {
            if let Some(name_node) = n.children().find(|c| c.tag_name().name() == "name") {
                name_node.text() == Some(name)
            } else {
                false
            }
        })
        .collect();
    
    Ok(nodes)
}

This approach completely avoids string-based XPath construction, eliminating the injection vector.

For applications that must use string-based XPath, implement strict input validation in Actix middleware:

use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error};
use actix_web::middleware::Transform;

struct XPathSanitizer;

impl<S, B> Transform<S> for XPathSanitizer
where
    S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = Error;
    type InitError = ();
    type Transform = XPathSanitizerMiddleware<S>;

    fn new_transform(&self, service: S) -> Result<Self::Transform, Self::InitError> {
        Ok(XPathSanitizerMiddleware { service })
    }
}

struct XPathSanitizerMiddleware<S> {
    service: S,
}

impl<S, B> Service for XPathSanitizerMiddleware<S>
where
    S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = Error;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;

    fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
        self.service.poll_ready(cx)
    }

    fn call(&mut self, mut req: ServiceRequest) -> Self::Future {
        // Sanitize query parameters that might be used in XPath
        if let Some(name) = req.query_string().get("name") {
            if contains_xpath_injection(name) {
                return Box::pin(async move {
                    Ok(req.into_response(
                        HttpResponse::BadRequest()
                            .body("Invalid input detected")
                            .into_body(),
                    ))
                });
            }
        }
        
        let fut = self.service.call(req);
        Box::pin(async move { fut.await.map(|res| res.map_into_left_body::<()>()) })
    }
}

fn contains_xpath_injection(input: &str) -> bool {
    let dangerous_chars = ["'", "\"", "//", "|", "&", "="];
    dangerous_chars.iter().any(|c| input.contains(c))
}

Register this middleware in your Actix app:

App::new()
    .wrap(XPathSanitizer)
    .service(search_user)
    .service(other_routes)

For comprehensive protection, combine input validation with least-privilege XML processing. Limit XPath queries to specific document sections and avoid allowing queries that can access external entities or documents.

Frequently Asked Questions

How does XPath injection differ from SQL injection in Actix applications?
While both involve injection attacks, XPath injection targets XML document structures rather than database tables. In Actix, XPath injection typically occurs when processing XML APIs or XML-based data stores, whereas SQL injection affects database interactions. The remediation approaches also differ: XPath injection requires XML-specific input validation and safe query construction, while SQL injection uses parameterized queries and ORM features.
Can middleBrick detect XPath injection in Actix applications that use WebAssembly or other non-standard runtimes?