Application Security

LDAP Injection Prevention Guide

LDAP injection attacks manipulate directory service queries to bypass authentication, extract sensitive data, and enumerate user accounts. This guide covers attack techniques and practical defenses for applications using LDAP.

James
Penetration Tester
6 min read

LDAP injection is the forgotten sibling of SQL injection. While SQL injection gets the headlines, LDAP injection quietly compromises enterprise authentication systems, Active Directory environments, and corporate intranets. Any application that authenticates users against an LDAP directory or searches directory data based on user input is a potential target.

The attack surface is significant. LDAP directories store user accounts, group memberships, organizational structures, and access control information for most enterprise environments. Compromising LDAP queries means compromising the identity infrastructure that everything else depends on.

How LDAP Queries Work

LDAP queries use a filter syntax based on parentheses and operators:

  • Simple filter: (cn=John Smith)
  • AND filter: (&(cn=John Smith)(department=Engineering))
  • OR filter: (|(cn=John)(cn=Jane))
  • NOT filter: (!(cn=John Smith))
  • Wildcard: (cn=J*)
  • Presence: (cn=*)

When an application builds LDAP filters by concatenating user input, the same class of injection vulnerabilities that plague SQL applies to LDAP.

Authentication Bypass

The most common LDAP injection target is authentication. A typical vulnerable login function builds a filter like:

(&(uid=[username])(userPassword=[password]))

If the attacker supplies *)(uid=*))(|(uid=* as the username, the filter becomes:

(&(uid=*)(uid=*))(|(uid=*)(userPassword=anything))

This matches any user with any UID -- effectively bypassing authentication. The LDAP server returns the first matching entry, which is usually an administrative account.

Simpler bypass payloads include:

  • Username: * -- matches any UID
  • Username: admin)(&) -- closes the filter and adds an always-true condition
  • Username: admin)(|(password=* -- modifies the filter logic

Prevention:

  • Never concatenate user input into LDAP filters
  • Use parameterized LDAP queries (LDAP libraries support this)
  • Validate that username and password contain only expected characters
  • Escape special LDAP characters: (, ), *, \, NUL

Data Extraction Through LDAP Injection

Beyond authentication bypass, LDAP injection can extract directory information:

Attribute enumeration. By injecting wildcards and observing response differences, attackers can enumerate user attributes, group memberships, and organizational structure.

Blind LDAP injection. When the application does not return LDAP query results directly, boolean-based blind injection can extract data character by character. The attacker tests conditions like (uid=a*) and observes whether the response indicates a match or not.

For example, to extract the admin's password hash:

  1. Test (&(uid=admin)(userPassword=a*)) -- does it match?
  2. Test (&(uid=admin)(userPassword=b*)) -- does it match?
  3. Continue until the first character is found
  4. Repeat for subsequent characters

User enumeration. Injecting into search filters reveals which usernames exist:

  • (uid=alice) returns results -- alice exists
  • (uid=bob) returns no results -- bob does not exist

Prevention:

  • Return generic error messages that do not reveal whether the query matched
  • Rate limit authentication and search endpoints
  • Log and alert on queries with special characters
  • Monitor for sequential or patterned queries indicating blind injection

LDAP Injection in Search Functions

Many enterprise applications include LDAP-backed search functionality -- employee directories, address books, group management. These search functions often accept user input that goes directly into LDAP filters:

Directory search poisoning. A search for employees in the "Engineering" department builds the filter (department=[input]). The attacker submits Engineering)(uid=* to extract all UIDs regardless of department.

Group membership manipulation. Applications that manage LDAP group memberships based on user input can be tricked into adding users to groups they should not belong to, such as Domain Admins.

Organizational unit traversal. LDAP queries specify a base DN (distinguished name) for the search. If the base DN is influenced by user input, the attacker can redirect the search to a different part of the directory tree.

Prevention:

  • Sanitize all input used in LDAP search filters
  • Restrict search base DNs to expected organizational units
  • Use LDAP access controls to limit what the application's service account can read
  • Apply the principle of least privilege to the LDAP bind account

Special Characters and Encoding

LDAP filter injection relies on special characters. Proper escaping neutralizes the attack:

Characters that must be escaped in LDAP filters:

  • ( -- \28
  • ) -- \29
  • * -- \2a
  • \ -- \5c
  • NUL -- \00

Characters that must be escaped in LDAP DNs:

  • , + " \ < > ; and leading/trailing spaces

Most LDAP libraries provide escaping functions. Use them:

// Java LDAP escaping
String safeFilter = "(uid=" + Filter.encodeValue(username) + ")";
# Python ldap3 escaping
from ldap3.utils.conv import escape_filter_chars
safe_filter = f"(uid={escape_filter_chars(username)})"
// C# escaping
string safeUsername = username
    .Replace("\\", "\\5c")
    .Replace("(", "\\28")
    .Replace(")", "\\29")
    .Replace("*", "\\2a")
    .Replace("\0", "\\00");

Secure LDAP Implementation

Use parameterized queries. Modern LDAP libraries support parameterized filters that handle escaping automatically:

// Java - parameterized search
SearchControls controls = new SearchControls();
String filter = "(&(uid={0})(userPassword={1}))";
NamingEnumeration<SearchResult> results =
    ctx.search(baseDN, filter, new Object[]{username, password}, controls);

Validate input strictly. Usernames should be alphanumeric with limited special characters. Reject any input containing LDAP metacharacters before it reaches the query builder.

Use LDAP bind for authentication. Instead of searching for a user with a matching password, attempt to bind (authenticate) to the LDAP server as that user. This delegates authentication to the LDAP server itself, eliminating the password comparison query entirely:

// Bind as the user instead of searching for password match
Hashtable<String, String> env = new Hashtable<>();
env.put(Context.SECURITY_PRINCIPAL, "uid=" + escapeDN(username) + ",ou=users,dc=example,dc=com");
env.put(Context.SECURITY_CREDENTIALS, password);
DirContext userCtx = new InitialDirContext(env);

Use LDAPS. Always use LDAP over TLS (LDAPS on port 636 or StartTLS on port 389). Unencrypted LDAP transmits credentials in cleartext and is vulnerable to interception and modification.

Restrict service account permissions. The application's LDAP service account should have the minimum permissions required. Read-only access to specific organizational units is sufficient for most authentication use cases.

Active Directory Specific Concerns

Active Directory is the most common LDAP directory in enterprise environments and has additional attack surface:

  • NTLM relay attacks can be triggered if LDAP traffic is unencrypted
  • Kerberoasting targets service accounts discoverable through LDAP queries
  • Password spraying uses LDAP to enumerate valid accounts before attempting authentication
  • DCSync attacks require specific LDAP permissions that overly permissive service accounts might have

Harden AD-specific configurations:

  • Require LDAP signing and channel binding
  • Enable LDAP logging for sensitive operations
  • Restrict which accounts can perform LDAP searches
  • Monitor for unusual LDAP query patterns

How Safeguard.sh Helps

Safeguard.sh monitors your LDAP libraries and directory service dependencies for known injection vulnerabilities and insecure defaults. When a CVE is published for an LDAP library in your dependency tree -- whether it is a filter injection bypass, a TLS validation flaw, or an authentication weakness -- Safeguard.sh alerts your team immediately. By tracking the security posture of every component that touches your directory infrastructure, Safeguard.sh helps ensure that your LDAP integration remains secure as new vulnerabilities are discovered.

Never miss an update

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