Browse learn

LDAP Injection

Learn how unsafe LDAP filter and distinguished-name construction causes injection flaws, and how escaping, validation, and safer APIs prevent them.

On this page

What is LDAP Injection?

LDAP injection is a security vulnerability that arises when applications construct Lightweight Directory Access Protocol (LDAP) filter queries by directly embedding untrusted input—typically user-supplied data—without proper validation or escaping. This flaw allows attackers to manipulate the logical structure of a directory query, leading to sensitive data exposure, unauthorized access, or privilege escalation. The root cause is the expressive syntax of LDAP filters, which enables attackers to inject special metacharacters and operators that alter the query’s behavior.

LDAP injection can surface anywhere an application integrates with a directory service and composes LDAP filters using data from outside the trusted code base. This includes, but is not limited to, user authentication, account lookup, group or role checks, and administrative queries. The risk affects all application architectures and technology stacks that build directory queries from user-controlled input—including applications written in Node.js, TypeScript, or those integrating with Active Directory—because the underlying vulnerability stems from the way the LDAP protocol itself interprets filter strings.

Example: Suppose an application builds a login filter like:

text
(&(uid=USERNAME)(userPassword=PASSWORD))

If USERNAME or PASSWORD are included in the filter without strict validation or escaping, an attacker can supply crafted input that alters the filter logic, possibly bypassing authentication altogether.

Understanding LDAP Filter Syntax

LDAP filter syntax, defined by RFC 4515, gives the protocol its power and its risk. An LDAP filter is a string-encoded logical expression, using a combination of attributes, comparisons, logical operators, and parentheses. Filters determine what entries a directory query will match.

Key Elements Enabling Injection

  • *: Wildcard (matches any value)
  • ( and ): Parentheses define structure and control evaluation order
  • &, |, !: Logical AND, OR, and NOT
  • =: Attribute-value comparison

Valid filter example:

text
(&(objectClass=user)(|(cn=alice)(cn=bob)))

This filter matches directory entries where objectClass is user and cn is either alice or bob.

When an application inserts raw user input (such as a username) straight into the filter string, an attacker can supply characters like *, ), or construct fragments such as )(|(cn=*)), restructuring the logic or forcing matching on unintended entries.

Manipulating filter logic with crafted input: Suppose the username supplied is *)(|(cn=*))). The resulting filter might look like:

text
(&(cn=*)(|(cn=*))(userPassword=...))

Here, the payload closes the intended filter expression and injects an OR clause that will always match, potentially enabling unauthorized login.

LDAP Injection Attack Scenarios

LDAP injection vulnerabilities arise wherever filters are built from untrusted input. Below are concrete examples illustrating how attackers craft payloads to interfere with intended directory logic.

Authentication Bypass Example

Given an authentication filter:

text
(&(uid=<input_username>)(userPassword=<input_password>))

If the attacker supplies the following username:

text
*)(uid=*))(|(uid=*

The constructed filter becomes:

text
(&(uid=*)(uid=*))(|(uid=*)(userPassword=<input_password>))

The injected )(uid=*))(|(uid=* segment manipulates the logic so the OR section always matches, which may allow authentication as any user, bypassing password checks.

Privilege Escalation Example

Suppose a system checks group membership as follows:

text
(&(member=<input_dn>)(cn=admins))

An attacker injects the following value for <input_dn>:

text
*)(cn=admins)(|(member=*)

This makes the filter:

text
(&(member=*)(cn=admins)(|(member=*)))

Now, the OR condition may include any directory entry, undermining access controls and potentially granting admin privileges to unauthorized users.

Data Exfiltration Example

Consider a user search feature where a filter is constructed using user input:

text
(&(objectClass=person)(cn=<search_input>))

If an attacker enters *)(|(mail=*)), the filter becomes:

text
(&(objectClass=person)(cn=*)(|(mail=*)))

This filter could return all directory entries where the mail attribute is set, effectively extracting all user email addresses. This shows how poorly validated input can allow attackers to exfiltrate more data than intended, especially when wildcards or logical operators are injected.

Blind LDAP Injection

In blind LDAP injection attacks, the application does not directly return the results of the directory query. However, attackers can still infer information by carefully constructing payloads and observing secondary application responses, such as whether a login succeeds, whether an error message is shown, or other subtle signals (including sometimes timing differences).

For example, an attacker may iteratively adjust injected filter segments and, based on binary feedback (success/failure), determine whether a particular user exists, whether a password matches, or whether a sensitive group membership is in place. Over multiple attempts, even without visible query results, an attacker can map out directory structure or user attributes.

Risks: What Can Go Wrong?

LDAP injection can lead to serious security breaches, including:

  • Authentication Bypass: Attackers log in as any user, or access accounts without providing valid credentials, by injecting filter-altering payloads.
  • Data Exposure: Illegitimate queries crafted via injection can enumerate users, reveal email addresses, or return sensitive organizational data.
  • Privilege Escalation: Manipulated group membership filters or role checks may enable attackers to assume higher privileges than intended.
  • Broad Directory Abuse: In extreme cases, attackers can enumerate, explore, or use information gleaned from the directory to stage further attacks.

It is critical to recognize that injection risks extend beyond authentication flows; any application feature that composes LDAP filters from potentially untrusted input—such as password reset, group or role queries, or administrative search tools—is a possible target.

How to Prevent LDAP Injection

Effective LDAP injection prevention requires combining strict input validation with standards-compliant escaping, and using safe APIs wherever possible.

Escaping Input per RFC 4515

RFC 4515 specifies which characters must be escaped in LDAP filter values when they are to be treated as literal data. Escaping prevents these characters from being interpreted as part of filter logic:

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

Example of escaping: If user input is *)(|(uid=*))), correct escaping transforms it into a string where filter-control characters are replaced with their escape sequences, ensuring user-supplied input cannot terminate or alter filter logic.

Input Validation

Escaping is necessary but should be paired with strong validation:

  • Restrict input size and type: Only allow expected character classes (e.g., alphanumeric for usernames).
  • Reject dangerous patterns: Where possible, block metacharacters or potentially dangerous patterns outright.
  • Prohibit user input as filter fragments: Only incorporate input as attribute values, never as raw filter pieces.

Secure Filter Construction

  • Avoid string concatenation of filters: Never assemble filter strings by concatenating raw user input.
  • Use safe construction APIs: Some LDAP libraries and frameworks provide filter-building methods or parameterized query functions that safely handle escaping. Availability of such APIs varies: for example, certain Java libraries offer this, but in Node.js and TypeScript environments, popular packages may lack built-in safe construction—developers often must implement escaping themselves.
  • Apply defenses in depth: Always validate and escape, even if using convenience functions, as not all platforms guarantee safety by default.

Audit Beyond Authentication

Review all places in your application where LDAP filters are built from dynamic input—not only login or authentication, but also group lookups, directory searches, and administrative actions.

LDAP Injection vs. SQL Injection (and Common Misconceptions)

While LDAP injection shares its root cause with SQL injection—the unsanitized interpolation of untrusted input into a query language—the syntax and exploitation mechanics of LDAP filters are distinct:

  • DN vs. Filter Escaping: Escaping rules for distinguished names (DNs) differ from those for filter values. Using the wrong escaping routine creates subtle vulnerabilities. Always use escaping appropriate to the LDAP context.
  • Escaping in Isolation is Not Sufficient: Relying solely on character escaping is dangerous; validation must restrict input to valid, expected patterns to prevent logic abuse even when metacharacters are neutralized.
  • Not Limited to Authentication: Any filter built with dynamic input can be a vulnerability—this includes password resets, group assignments, or user searches, not just authentication.
  • Alphanumeric Input Can Still Be Dangerous: Even seemingly harmless input may cause filter logic surprises if interpreted out of its intended context.

Practical Advice for Secure LDAP Integrations

To defend against LDAP injection, adopt these essential practices:

  • Audit filter construction everywhere: Review your codebase for places where LDAP filters are built from untrusted input.
  • Validate inputs strictly: Restrict what users can submit to only valid, expected forms for your application domain.
  • Always escape input for filter values per RFC 4515: Every time untrusted data enters a filter, apply correct escaping.
  • Prefer safe APIs when available: Some LDAP client libraries provide filter constructors or parameterized methods. For example, Java and .NET frameworks offer such APIs, but Node.js and TypeScript environments may require manual escaping—be explicit about your stack’s behavior.
  • Test for injection: Regularly test your application for LDAP injection, including blind vectors, as part of security review or penetration testing.
  • Treat DNs and Filter Values Differently: Use context-specific escaping and validation for each part of an LDAP query; never confuse filter-value and DN escaping logic.

LDAP injection is a risk native to the flexibility and power of LDAP filter syntax. Preventing it requires knowledgeable, standards-driven implementation: strictly validate input, always escape per RFC 4515, and avoid constructing filters via concatenated strings. Secure integrations depend as much on understanding LDAP’s quirks as on applying familiar security hygiene. Recognize every place dynamic input meets filter construction, and use both validation and proper escaping, using the right routines for the filter and distinguished name contexts.

Sources