HIGH ldap injectionactix

Ldap Injection in Actix

How Ldap Injection Manifests in Actix

Ldap Injection in Actix applications typically occurs when user input is directly incorporated into LDAP queries without proper sanitization. Actix developers often use LDAP for authentication backends, directory services, or user management systems, making this vulnerability particularly relevant.

use actix_web::{web, App, HttpServer, Responder};
use ldap3::{Ldap, Scope, SearchOptions};

async fn search_users(query: web::Query<UserQuery>) -> impl Responder {
    let ldap = Ldap::new("ldap://localhost:389").unwrap();
    let base_dn = "ou=users,dc=example,dc=com";
    
    // Vulnerable: direct interpolation of user input
    let filter = format!("(&(objectClass=person)(cn={}))", query.name);
    
    let (result, _err) = ldap.search(
        base_dn,
        Scope::Sub,
        &filter,
        vec!["cn", "mail"]
    ).await.unwrap();
    
    serde_json::to_string(&result).unwrap()
}

struct UserQuery { name: String }

The vulnerability in this Actix handler is clear: the query.name parameter is directly interpolated into the LDAP filter string. An attacker could submit a payload like *)(objectClass=*))(|(objectClass=* to bypass authentication or extract sensitive directory information. The lack of parameterized queries means LDAP injection is possible.

Another common pattern in Actix applications involves using LDAP for authentication with Active Directory or OpenLDAP backends:

async fn authenticate(credentials: web::Json<Credentials>) -> impl Responder {
    let ldap = Ldap::new("ldap://ad.example.com").unwrap();
    let user_dn = format!("cn={},ou=users,dc=example,dc=com", credentials.username);
    
    // Vulnerable: username directly interpolated into DN
    match ldap.simple_bind(&user_dn, &credentials.password).await {
        Ok(_) => HttpResponse::Ok().finish(),
        Err(_) => HttpResponse::Unauthorized().finish()
    }
}

struct Credentials { username: String, password: String }

Here, an attacker could craft a username like admin),dc=example,dc=com (|(cn=* to manipulate the bind DN and potentially authenticate as a different user without knowing their password.

Actix-Specific Detection

Detecting LDAP injection in Actix applications requires examining both the code patterns and runtime behavior. middleBrick's black-box scanning approach is particularly effective for this, as it can test the unauthenticated attack surface without requiring source code access.

When scanning an Actix API endpoint that might be vulnerable to LDAP injection, middleBrick tests for several attack patterns:

POST /api/search HTTP/1.1
Host: example.com
Content-Type: application/json

{
  "name": "*)(objectClass=*))(|(objectClass=*"
}

POST /api/authenticate HTTP/1.1
Host: example.com
Content-Type: application/json

{
  "username": "admin),dc=example,dc=com\n(|(cn=*",
  "password": "irrelevant"
}

POST /api/search HTTP/1.1
Host: example.com
Content-Type: application/json

{
  "name": "*")(&(objectClass=person)(mail=*)(cn=*")"
}

These payloads test for common LDAP injection patterns including filter manipulation, DN manipulation, and attribute injection. middleBrick's 12 security checks include specific LDAP injection detection that analyzes responses for signs of successful injection, such as unexpected results, error messages revealing directory structure, or authentication bypass.

For Actix developers, the CLI tool provides a quick way to scan your own endpoints:

npx middlebrick scan https://api.example.com/search?name=test

# Or scan with the npm package installed
middlebrick scan --url https://api.example.com/authenticate --method POST --data '{"username":"test","password":"test"}'

The scanner will report findings with severity levels and provide remediation guidance specific to LDAP injection patterns found in your Actix application.

Actix-Specific Remediation

Remediating LDAP injection in Actix applications requires using parameterized queries or proper input sanitization. The ldap3 crate provides mechanisms to safely construct LDAP queries without string interpolation.

Here's a secure version of the search endpoint:

use actix_web::{web, App, HttpServer, Responder};
use ldap3::{Ldap, Scope, SearchOptions, Escape};

async fn search_users(query: web::Query<UserQuery>) -> impl Responder {
    let ldap = Ldap::new("ldap://localhost:389").unwrap();
    let base_dn = "ou=users,dc=example,dc=com";
    
    // Secure: use parameterized query with proper escaping
    let filter = format!("(&(objectClass=person)(cn={}))", Escape::ldap(&query.name));
    
    let (result, _err) = ldap.search(
        base_dn,
        Scope::Sub,
        &filter,
        vec!["cn", "mail"]
    ).await.unwrap();
    
    serde_json::to_string(&result).unwrap()
}

struct UserQuery { name: String }

The key change is using Escape::ldap() to properly escape special LDAP characters. This prevents injection by ensuring user input cannot break out of the intended query structure.

For authentication endpoints, use the built-in bind mechanism with proper DN construction:

async fn authenticate(credentials: web::Json<Credentials>) -> impl Responder {
    let ldap = Ldap::new("ldap://ad.example.com").unwrap();
    
    // Secure: use parameterized bind with escaped DN
    let user_dn = format!("cn={},ou=users,dc=example,dc=com", Escape::ldap(&credentials.username));
    
    match ldap.simple_bind(&user_dn, &credentials.password).await {
        Ok(_) => HttpResponse::Ok().finish(),
        Err(_) => HttpResponse::Unauthorized().finish()
    }
}

struct Credentials { username: String, password: String }

Alternatively, use a more robust authentication approach with proper error handling:

async fn authenticate(credentials: web::Json<Credentials>) -> impl Responder {
    let ldap = Ldap::new("ldap://ad.example.com").unwrap();
    
    // Use a safer approach with proper DN escaping
    let escaped_user = Escape::ldap(&credentials.username);
    let user_dn = format!("cn={},ou=users,dc=example,dc=com", escaped_user);
    
    // Check if the DN is valid before attempting bind
    if !is_valid_dn(&user_dn) {
        return HttpResponse::BadRequest().body("Invalid username format");
    }
    
    match ldap.simple_bind(&user_dn, &credentials.password).await {
        Ok(_) => HttpResponse::Ok().finish(),
        Err(_) => HttpResponse::Unauthorized().finish()
    }
}

fn is_valid_dn(dn: &str) -> bool {
    // Simple validation to prevent DN injection
    !dn.contains("\n") && !dn.contains("\r") && dn.len() < 255
}

For production Actix applications, consider using middleware to validate and sanitize LDAP inputs across all endpoints:

use actix_web::{dev::Payload, web::Data, FromRequest, HttpRequest};

struct LdapSafeString(String);

#[async_trait::async_trait]
impl FromRequest for LdapSafeString {
    type Error = actix_web::Error;
    type Future = Ready<Result<Self, Self::Error>>;
    type Config = ();
    
    async fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future::Output {
        // Extract and sanitize input
        let input = req.match_info().get("param").unwrap_or("").to_string();
        let safe = Escape::ldap(&input);
        ready(Ok(LdapSafeString(safe)))
    }
}

async fn secure_search(ldap_safe: LdapSafeString) -> impl Responder {
    // ldap_safe.0 is now safe to use in LDAP queries
    HttpResponse::Ok().body(format!("Searching for: {}", ldap_safe.0))
}

Frequently Asked Questions

How can I test my Actix API for LDAP injection vulnerabilities?
Use middleBrick's black-box scanning to test your Actix endpoints without requiring credentials or source code access. The scanner tests for LDAP injection patterns including filter manipulation, DN injection, and attribute injection. You can also manually test by sending payloads with special LDAP characters like *, (, ), and | to see if you can manipulate query results or bypass authentication.
What's the difference between LDAP injection and SQL injection in Actix applications?
Both involve injecting malicious input to manipulate queries, but LDAP injection targets directory services while SQL injection targets databases. In Actix, LDAP injection commonly appears in authentication and directory search endpoints, while SQL injection appears in database-driven APIs. LDAP injection often uses different syntax (LDAP filters vs SQL WHERE clauses) and can lead to directory traversal, authentication bypass, and information disclosure about the directory structure.